diff --git a/Build/Resources/Public/Less/form.less b/Build/Resources/Public/Less/form.less
index 92969d29cbd3fdbc1ff27101daa65bd3d6333542..b7d0033a58d874913ef2e453778f228c721d22f9 100644
--- a/Build/Resources/Public/Less/form.less
+++ b/Build/Resources/Public/Less/form.less
@@ -1,703 +1,948 @@
 @charset "UTF-8";
 
-.std-em-selector {
-  font-size: 90%;
-  font-style: normal;
+//
+// Variables
+//
+// @toDo remove these variables after including this file in backend.less
+// Bootstrap: variables.less
+@panel-default-text: @gray-dark;
+
+// /Build/Resources/Public/Less/cropper/variables.less
+@screen-lg: 1200px; // Large screen / wide desktop
+
+// /Build/Resources/Public/Less/_variables.less
+@gray-dark: rgb(90, 90, 90);
+@gray: rgb(115, 115, 115);
+@brand-primary: #0078e6;
+@brand-success: #79a548;
+@brand-info: #6daae0;
+@brand-warning: #e8a33d;
+@brand-danger: #c83c3c;
+@table-bg: #fafafa;
+@table-bg-hover: darken(@table-bg, 5%);
+@panel-default-heading-bg: #ddd;
+@text-color: #000;
+@btn-default-bg: #eee;
+@btn-default-border: #bbb;
+
+// /Build/Resources/Public/Less/Component/module.less
+@module-docheader-height: 65px;
+@module-docheader-border: #c3c3c3;
+
+// /Build/Resources/Public/Less/TYPO3/_module_web_page.less
+@page-ce-header-hover-bg: #d0d0d0;
+
+// /Build/Resources/Public/Less/TYPO3/_element_tree.less
+@navigation-bg: #f5f5f5;
+
+// Form Variables
+@stage-max-width: 600px;
+@stage-abstract-element-height: 62px;
+@stage-abstract-element-toolbar-height: 35px;
+@stage-icon-container-width: 40px;
+@stage-validation-list-width: 100px;
+@stage-breakpoint: (@screen-lg + 100);
+@stage-validation-transition-time-in: 0.2s;
+@stage-validation-transition-time-out: 0.3s;
+
+@stage-background-color: #fafafa;
+@stage-element-toolbar-background: #d0d0d0;
+@collection-element-background: @page-ce-header-hover-bg;
+
+//
+// Mixins
+//
+
+.fade-out-gradient-effect-bottom (@color, @gradient-start-height, @gradient-height) {
+  &:before, &:after {
+    display: block;
+    content: '';
+    position: absolute;
+    bottom: 0;
+    right: 0;
+    left: 0;
+  }
+  &:before {
+    height: @gradient-start-height;
+    background: @color;
+  }
+  &:after {
+    bottom: @gradient-start-height;
+    height: @gradient-height;
+    background: linear-gradient(to bottom, rgba(red(@color), green(@color), blue(@color), 0) 0%, @color 100%);
+  }
 }
 
-.std-strong-selector {
-  display: block;
-  font-size: 90%;
-  font-weight: normal;
-  color: #C00;
+.selected-button-style-primary () {
+  .btn {
+    background-color: #fff;
+    border-color: #fff;
+    &:hover, &.active {
+      background-color: lighten(@brand-info, 30%);
+    }
+  }
+  .icon {
+    svg path {
+      fill: @brand-primary;
+    }
+  }
 }
 
-.std-li-selector{
-  float: none;
-  width: auto;
-  margin-right: 0;
-  margin-left: 1em;
+.collapsed-icon-animation () {
+  transform: rotate(0deg);
+  transition: transform 0.2s;
 }
-#fake-form {
-
-  ol {
-    padding-left: 0 !important;
-    list-style: none !important;
-  }
 
-  /* style for each form element */
-  li {
-    overflow: hidden;
-    padding: 0.5em;
-    margin-bottom: 0.5em;
-
-    &#element-placeholder{
-      padding: 0;
-      margin: 0;
-    }
+.expanded-icon-animation () {
+  transform: rotate(90deg);
+  transition: transform 0.2s;
+}
 
-    input + label,
-    textarea + label,
-    select + label {
-      .std-li-selector;
-    }
+//
+// X-Component
+//
+.t3-form-x-component {
+  position: absolute;
+  top: 0;
+  height: 100%;
+  line-height: normal;
+  background: @navigation-bg;
 
-    textarea + label {
-      vertical-align: top;
-    }
+  a {
+    text-decoration: none;
   }
-
-  textarea, input[type=text]{
-    border: 1px solid #c0c0c0;
+  ol,
+  ul {
+    list-style: none;
+    padding: 0;
   }
-
-  input[type=text]{
-    // equal width like textareas
-    width:300px;
-    padding: 3px;
+  .ui-sortable-placeholder {
+    outline-offset: -1px !important;
   }
+}
 
-  label {
-    display:block;
-    margin-right: 1em;
-    vertical-align: baseline;
+.t3-form-x-component-inner-wrapper {
+  padding: 1.5em;
+}
 
-    em{
-      .std-em-selector;
-    }
+//
+// Structure Tree
+//
+#t3-form-navigation-component {
+  overflow: hidden;
+  left: 0;
+}
 
-    strong{
-      .std-strong-selector;
-    }
-  }
+#t3-form-structure-panel {
+  overflow: auto;
+  padding-top: @module-docheader-height;
+  height: 100%;
 
-  .x-checkbox, .x-radio{
-    label{
-      display:inline-block;
-    }
+  .icon {
+    z-index: 1;
   }
-
-  legend {
-    border-bottom:0;
-    em{
-      .std-em-selector;
-    }
-
-    strong{
-      .std-strong-selector;
-    }
+  #t3-form-navigation-component-tree-root-container, .tree li > div {
+    border: 1px solid transparent;
+    cursor: pointer;
   }
-
-  fieldset {
-    position: relative;
-    margin: 0;
-    padding: 0;
-
-    &.submit {
-      border-style: none;
-    }
-
-    &.fieldset-horizontal {
-      border-width: 0;
-
-      &.label-below label {
-        display: block;
-        margin-left: 0;
-        margin-top: 0.2em;
-        font-size: 90%;
-        text-align: left;
-        color: #999999;
-      }
-
-      label{
-        em {
-          display: inline;
-        }
-      }
-
-      ol {
-        padding: 0;
+  .tree {
+    .svg-wrapper {
+      svg {
+        overflow: visible;
+        position: relative;
+        top: -0.8em;
+        left: 0.6em;
       }
-
-      li {
-        float: left;
-        margin-right: 1em;
-        padding: 0;
+      path {
+        fill: none;
+        shape-rendering: crispEdges;
+        stroke: rgb(221, 221, 221);
+        stroke-width: 1;
       }
     }
-
-    &.fieldset-subgroup {
-      margin-bottom: -2em;
-      border-style: none;
-
-      ol {
-        position: relative;
-        top: -1.4em;
-        padding: 0;
-      }
-
-      li {
-        padding: 0;
+    li {
+      white-space: nowrap;
+      .icon-actions-pagetree-collapse {
+        margin-right: 0.3em;
+        img {
+          .expanded-icon-animation ();
+        }
       }
-
-      legend {
-        margin-left: 0;
-        padding: 0;
+      &.mjs-nestedSortable-collapsed {
+        > ol {
+          display: none;
+        }
+        .icon-actions-pagetree-collapse img {
+          .collapsed-icon-animation ();
+        }
       }
-
-      input + label {
-        float: none;
-        width: auto;
-        display: inline;
-        margin: 0 0 0 1em;
+      small {
+        padding-left: 0.5em;
+        font-size: 80%;
       }
     }
-  }
-
-  legend {
-    font-size: 12px;
-    font-weight: bold;
-    color: #000000;
-
-    em {
-      position: absolute;
-    }
-
-    strong {
-      position: absolute;
-      top: 1.4em;
+    .t3-form-icon {
+      margin-right: 0.5em;
+      margin-left: 0.5em;
     }
-  }
-
-  /* labels as block, labels displayed above or below the input fields */
-  .labels-block{
-    label {
-      display: block;
-      float: none;
-      margin: 0 0 0.5em;
-      width: auto;
+    .t3-form-element-has-children > div .t3-form-icon {
+      margin-left: 0.1em;
     }
-
-    input + label,
-    textarea + label{
-      margin: 0.5em 0 0;
+    .sortable-hover {
+      outline: 1px solid darken(@panel-default-heading-bg, 20%);
     }
-
+  }
+  .tree li > div:hover,
+  .t3-form-form-element-selected,
+  #t3-form-navigation-component-tree-root-container:hover,
+  .t3-form-root-element-selected {
+    background-color: darken(@navigation-bg, 1%);
+    border-color: darken(@navigation-bg, 10%);
+    border-radius: 2px;
+    margin-left: -2em;
+    padding-left: 2em;
+    margin-right: -1.3em;
+  }
+  .tree li > .t3-form-form-element-selected,
+  .tree li > .t3-form-form-element-selected:hover,
+  #t3-form-navigation-component-tree-root-container.t3-form-root-element-selected,
+  #t3-form-navigation-component-tree-root-container.t3-form-root-element-selected:hover {
+    background-color: #fff;
+    border-color: darken(@navigation-bg, 10%);
+  }
+  .t3-form-x-component-inner-wrapper {
+    padding-top: 2.5em;
   }
 }
 
-/* labels alignment right */
-#fake-form .labels-alignment-right label,
-#fake-form .labels-alignment-right .fieldset-subgroup legend,
-#fake-form .labels-alignment-right.fieldset-subgroup legend {
-  text-align: right;
-}
-
-#fake-form .labels-block fieldset.fieldset-subgroup,
-#fake-form fieldset.labels-block.fieldset-subgroup {
-  margin-bottom: 0;
-}
-
-#fake-form .labels-block .fieldset-subgroup legend,
-#fake-form .labels-block.fieldset-subgroup legend {
-  width: auto;
-}
-
-#fake-form .labels-block .fieldset-subgroup legend em,
-#fake-form .labels-block.fieldset-subgroup legend em {
-  position: relative;
-}
-
-#fake-form .labels-block .fieldset-subgroup legend strong,
-#fake-form .labels-block.fieldset-subgroup legend strong {
-  position: relative;
-  top: 0;
-}
-
-#fake-form .labels-block .fieldset-subgroup ol,
-#fake-form .labels-block.fieldset-subgroup ol {
-  top: 0;
-  margin: 0;
-  padding: 0.5em 0 0;
-}
-
-/* element HIDDEN */
-#fake-form .formwizard-element.hidden-element {
-  cursor: default;
-}
-
-#fake-form .formwizard-element .hidden-dummy-element {
-  margin: 0;
-  padding: 5px;
-  border:1px dotted #A9A9A9;
+//
+// Inspector
+//
+.form-group.t3-form-collection-element-remove-button,
+.t3-form-inspector-finishers-editor-removeButton,
+.form-group.t3-form-inspector-validators-editor-removeButton {
+  margin: 0 !important;
+  font-size: 0;
 }
 
-/* styles for drag and drop content */
-.x-dd-drag-ghost .formwizard-element {
-  list-style:none;
+#t3-form-inspector-panels-container {
+  overflow: hidden;
+  right: 0;
+  padding-top: @module-docheader-height;
 }
 
-.x-dd-drop-icon {
-  top: 7px;
+#t3-form-inspector-panels {
+  overflow: auto;
+  height: 100%;
 }
 
-.x-dd-drag-ghost ol {
-  margin: 5px 0;
-  padding: 0;
-  list-style: none;
-}
+#t3-form-inspector {
+  padding: 1em 0.5em;
 
-.x-dd-drag-ghost .buttongroup,
-.x-dd-drag-ghost label em,
-.x-dd-drag-ghost label strong {
-  display: none;
+  h2,
+  h3,
+  h4 {
+    margin: 0;
+    padding: 0.1em 0.2em 0.2em 0.5em;
+    border-top: 1px solid @module-docheader-border;
+    clear: both;
+    font: inherit;
+    font-weight: bold;
+  }
+  h2 {
+    padding-bottom: 1em;
+    border: none;
+    border-bottom: 1px solid @module-docheader-border;
+  }
+  > h2:first-child {
+    border-top: none;
+  }
+  h3 {
+    color: @text-color;
+    padding-top: 0.3em;
+    border: none;
+  }
+  h4 {
+    padding: 0.8em 3em 0.8em 2.5em;
+    font-weight: 500;
+    background-color: @panel-default-heading-bg;
+    span[data-template-property="label"] {
+      vertical-align: top;
+    }
+  }
+  .t3-form-remove-element-button {
+    position: absolute;
+    top: 90px;
+    right: 2.5em;
+  }
+  .t3-form-control-group,
+  .t3-form-add-collection-element {
+    margin: 1.5em 0.5em;
+    clear: both;
+  }
+  .t3-form-inspector-editor-requiredValidator {
+    label {
+      cursor: pointer;
+    }
+  }
 }
 
-.x-dd-drag-ghost label {
-  margin: 0 10px 0 5px;
+//
+// Inspector Collection
+//
+.t3-form-add-collection-element {
+  padding-bottom: 1em;
 }
 
-.x-dd-drag-ghost legend {
-  margin: 0 5px;
-  font-size: 14px;
-  font-weight: bold;
-  color: #000;
-  border: none;
-}
+.t3-form-collection-container {
+  margin-top: -1em;
+  padding: 0.6em;
 
-.x-grid-panel .remove {
-  background-image: url("../Images/remove.gif");
-  width: 15px;
-  height: 16px;
+  .ui-sortable-handle {
+    cursor: auto;
+  }
+  h4 {
+    cursor: move;
+  }
+  .icon-actions-view-table-expand {
+    position: absolute;
+    left: 0.5em;
+  }
+  a.collapsed {
+    .icon-actions-view-table-expand svg {
+      .collapsed-icon-animation ();
+    }
+  }
+  a:not(.collapsed) {
+    .icon-actions-view-table-expand svg {
+      .expanded-icon-animation ();
+    }
+  }
 }
 
-.x-dd-drag-proxy,
-.x-dd-drop-nodrop {
-  background-color: #fff;
-  border-color: #c0c0c0;
+.t3-form-collection-element {
+  position: relative;
+  margin-bottom: 0.5em;
+  border: 1px solid @module-docheader-border;
+  border-top: none;
+  background: @navigation-bg;
+
+  .t3-form-collection-element-remove-button {
+    position: absolute;
+    right: 0.5em;
+    top: 0.6em;
+  }
 }
-.tab-content{
-  fieldset{
 
-    #formwizard{
-      display:inherit;
+//
+// Inspector Property Grid
+//
+.property-grid {
+  .form-control {
+    min-width: initial;
+    min-width: auto;
+    font-size: 0.9em;
+  }
+  .table {
+    th {
+      font-size: 0.9em;
     }
-
-    &.form-section{
-      float: left;
-      min-width: 380px;
-      width: 100%;
-      padding-bottom: 15px;
-
-      &:last-child{
-        margin-bottom: 1em;
+    > tbody > tr {
+      cursor: pointer;
+      background-color: @table-bg;
+      &:last-child {
+        cursor: auto;
       }
-
-      ol{
-        &#formwizard-right{
-          // overwrite inline-style "auto"
-          width:100vw !important;
-          overflow: visible !important;
-          position: relative;
-          float:none;
-          left:5px !important;
-          padding-top:0;
-          padding-left:0;
-          margin-right: 10px;
-          top:30px !important;
-          display: table-cell;
-          height:auto !important;
-          list-style: none;
-          border-top-style: none;
-
-          &.hover{
-            left:0;
-            width:auto;
-          }
+      > td {
+        padding: 0.6em 0.3em;
+        text-align: center;
+        &:first-child {
+          width: 35px;
+        }
+        &:nth-child(2), &:nth-child(3) {
+          width: 75px;
+        }
+        &:nth-child(4) {
+          width: 65px;
+        }
+        &:nth-child(5) {
+          width: 35px;
         }
       }
     }
+    .btn {
+      background-color: @btn-default-bg;
+      border-color: @btn-default-border;
+    }
   }
-}
-
-/* outer wrapper of whole wizard */
-#form-wizard-element {
-  z-index: 1;
-
-  #formwizard-left{
-    display: table-cell;
-    float:left !important;
-    margin-right: -1px;
-
-    .x-tab-panel-body{
-      // overwrite inline-styles with important ;(
-      height:100% !important;
-      overflow:visible !important;
+  .sort-row-field {
+    cursor: move;
+  }
+  .ui-sortable-helper {
+    td {
+      border: none;
     }
   }
+  .ui-sortable-placeholder {
+    height: 45px;
+    border-left: 1px solid @module-docheader-border !important;
+    border-right: 1px solid @module-docheader-border !important;
+    outline-offset: -5px !important;
+  }
 }
 
-/* inner wrapper of whole wizard */
-#formwizard {
-  background-color: #F8F8F8;
-}
-
-/* applied when a element is moved */
-#formwizard.hover-move {
-  cursor: move;
+//
+// Stage
+//
+#t3-form-stage-inner-container {
+  display: inline-block;
+  width: 90%;
+  text-align: left;
+  @media (min-width: @stage-breakpoint) {
+    width: @stage-max-width;
+  }
 }
 
-/* left panel */
-#formwizard-left.x-border-panel {
+#t3-form-stage-container {
+  overflow: auto;
   position: relative;
-  left: auto;
-  top: auto;
-}
-
-/* tabs */
-#formwizard-left .x-tab-panel-header {
-  background-color: transparent;
-}
-
-/* tabs inner */
-#formwizard-left .x-tab-strip {
-  margin-bottom: 0;
-}
-
-#formwizard-left .x-tab-strip-top .x-tab-left {
-  padding-right: 20px;
-}
-
-#formwizard-left .x-tab-strip-top .x-tab-right {
-  padding: 5px 10px 2px;
-  background-color: #EDEDED;
-  border-radius: 0;
-}
-
-#formwizard-left .x-tab-strip-top .x-tab-strip-active .x-tab-right,
-#formwizard-left .x-tab-strip-top .x-tab-strip-active.x-tab-strip-over .x-tab-right{
-  background-color: transparent;
-  border-bottom-color: #F8F8F8;
-}
-
-#formwizard-left .x-tab-strip-top .x-tab-strip-over .x-tab-right {
-  background-color: #E1E1E1;
-}
-
-#formwizard-left li.validation-error .x-tab-left,
-#formwizard-left div.validation-error .x-accordion-hd {
-  margin-right: 14px;
-  background-image: url("../../../../../t3skin/extjs/images/form/exclamation.gif");
-  background-position: right 1px;
-  background-repeat: no-repeat;
-}
-
-/* content below tabs */
-#formwizard-left .x-tab-panel-body-content {
-  min-height: 330px;
-  padding: 10px;
-  background: transparent;
-  border: 1px solid #C0C0C0;
-  border-top-width: 0;
-}
-
-/* info messages (also for drag and drop) */
-#formwizard-left .message-information,
-#fake-form .message-information,
-.x-dd-drag-ghost .message-information {
-  margin: 10px 0 15px 16px;
-  padding: 12px 10px;
-  background-image: none;
-  border-radius: 0;
-  box-shadow: none;
-}
-
-#formwizard-left .message-information p,
-#fake-form .message-information p,
-.x-dd-drag-ghost .message-information {
-  margin: 0;
-}
-
-/* intro info messages */
-#formwizard-left #formwizard-left-elements-intro,
-#formwizard-left #formwizard-left-options-dummy,
-#fake-form .message-information {
-  margin: 0 0 10px;
-}
-
-#formwizard-left .x-tab-panel-body,
-#formwizard-left .x-accordion-hd {
-  background: transparent none;
-  border-width: 0;
-}
-
-/* accordion */
-#formwizard-left .x-panel-accordion {
-  border-bottom: 1px solid #C7C7C7;
-}
-
-#formwizard-left .x-panel-accordion:last-child {
-  border-bottom: medium none;
-}
-
-/* headline of accordion */
-#formwizard-left .x-accordion-hd {
-  padding-left: 0;
-}
-
-/* toggle icon of accordion */
-#formwizard-left .x-accordion-hd .x-tool-toggle {
-  margin: 0;
-  float: left;
-  background-image: url("../Images/module-menu-down.png");
-  background-position: 0 4px;
-}
-
-#formwizard-left .x-panel-collapsed .x-accordion-hd .x-tool-toggle {
-  background-image: url("../Images/module-menu-right.png");
-  background-position: 1px 3px;
-}
-
-#formwizard-left .x-accordion-hd .x-panel-header-text {
-  font-weight: bold;
-}
-
-#formwizard-left .x-accordion-hd .x-panel-body {
-  padding-left: 15px;
-}
-
-/* element inside accordion */
-#formwizard-left .x-form {
-  margin-left: 15px;
-  margin-top: 10px;
-}
-
-#formwizard-left .x-form fieldset {
-  padding: 0;
-  border: none;
-}
-#formwizard-left .x-form fieldset legend {
-  padding: 0;
-  font-size: 12px;
-  color: #222222;
-}
-
-#formwizard-left .x-panel-tbar {
-  margin-top: 10px;
-  padding-left: 15px;
-  padding-bottom: 0;
-  border-width: 0;
-}
-
-#formwizard-left .x-panel-tbar .x-toolbar {
-  padding: 0;
-}
-
-#formwizard-left .x-table-layout {
-  margin-bottom: 10px;
-}
-
-/* generic element like textfield */
-#formwizard-left .formwizard-element {
-  margin-left: 12px;
-  background-color: transparent;
-  background-image: none;
-  border-color: transparent;
-}
-
-#formwizard-left .formwizard-element.x-btn-over {
-  background-color: #D5D5D5;
-  background-image: -moz-linear-gradient(center top , #F6F6F6 10%, #D5D5D5 90%);
-  border-color: #C0C0C0;
-  border-radius: 0;
-}
-
-#formwizard-left .formwizard-element .x-btn-mc {
+  height: 100%;
   text-align: left;
-}
-
-/* form elements in left panel */
-.formwizard-left-elements-basic-button {
-  background-image: url("../Images/ui-button.png");
-}
-
-.formwizard-left-elements-basic-checkbox {
-  background-image: url("../Images/ui-check-box.png");
-}
-
-.formwizard-left-elements-basic-fieldset {
-  background-image: url("../Images/ui-group-box.png");
-}
-
-.formwizard-left-elements-basic-fileupload {
-  background-image: url("../Images/drive-upload.png");
-}
-
-.formwizard-left-elements-basic-hidden {
-  background-image: url("../Images/ui-text-field-hidden.png");
-}
-
-.formwizard-left-elements-basic-password {
-  background-image: url("../Images/ui-text-field-password.png");
-}
-
-.formwizard-left-elements-basic-radio {
-  background-image: url("../Images/ui-radio-button.png");
-}
-
-.formwizard-left-elements-basic-reset {
-  background-image: url("../Images/broom.png");
-}
-
-.formwizard-left-elements-basic-select {
-  background-image: url("../Images/ui-combo-box.png");
-}
-
-.formwizard-left-elements-basic-submit {
-  background-image: url("../Images/ui-button-default.png");
-}
-
-.formwizard-left-elements-basic-textarea {
-  background-image: url("../Images/ui-scroll-pane-text.png");
-}
-
-.formwizard-left-elements-basic-textline {
-  background-image: url("../Images/ui-text-field.png");
-}
-
-.formwizard-left-elements-predefined-checkboxgroup {
-  background-image: url("../Images/ui-check-boxes.png");
-}
-
-.formwizard-left-elements-predefined-email {
-  background-image: url("../Images/mail.png");
-}
-
-.formwizard-left-elements-predefined-name {
-  background-image: url("../Images/user-silhouette.png");
-}
-
-.formwizard-left-elements-predefined-radiogroup {
-  background-image: url("../Images/ui-radio-buttons.png");
-}
-
-.formwizard-left-elements-content-header {
-  background-image: url("../Images/edit-heading.png");
-}
-
-.formwizard-left-elements-content-textblock {
-  background-image: url("../Images/edit-textblock.png");
-}
-
-#formwizard-left .x-form-text {
-  height: 17px;
-}
-
-#formwizard-left .x-btn-text-icon .x-btn-icon-small-left .x-btn-text {
-  color: black;
-}
-
-#formwizard-left .x-small-editor .x-form-text {
-  height: 13px !important;
-}
-
-/* icon in element field for applying entered text */
-#formwizard-left .x-form-field-wrap .x-form-submit-trigger {
-  background-image: url("../Images/submit-trigger.gif");
-}
-
-/* right panel */
-#formwizard-right {
-  min-height: 350px;
-  padding: 30px 0 10px 2px;
-  overflow: visible;
-}
-
-#fake-form {
-  padding: 10px;
-  background-color: tansparent;
-  border: 1px solid #C0C0C0;
-}
-
-#fake-form li {
-  overflow: visible;
-}
-
-/* visible area of element on right panel */
-#fake-form div.overflow-hidden {
-  overflow: hidden;
-
-  input{
-    margin-left: 1px;
+  @media (min-width: @stage-breakpoint) {
+    text-align: center;
   }
-}
 
-/* wrap around all elements on right panel */
-#fake-form .formwizard-element {
-  border: 1px solid transparent;
-  position: relative;
-}
+  ol,
+  ul {
+    list-style: none;
+  }
+  .form-section {
+    border: none;
+  }
+  .panel-heading {
+    button {
+      outline: none;
+    }
+    .paginiation-label {
+      margin-right: 1em;
+    }
+  }
+  .t3-form-new-element-container {
+    height: @stage-abstract-element-height;
+    border: 1px dashed @panel-default-heading-bg;
+    text-align: center;
+    padding-top: @stage-abstract-element-height/2;
+    .btn {
+      transform: translateY(-50%);
+    }
+  }
 
-#fake-form .formwizard-element.hover,
-#fake-form .formwizard-element.hidden.hover {
-  background-color: #F9FCFF;
-  border: 1px solid #C5DBE6;
-}
+  // Abstract
+  &.t3-form-stage-viewmode-abstract {
+    ol,
+    ul {
+      padding-left: @stage-icon-container-width;
+      padding-right: 1em;
+    }
+    .t3-form-page-title {
+      margin: 0 0 0.5em;
+    }
+    #t3-form-stage-inner-container {
+      overflow: hidden;
+    }
+    .t3-form-element-composit {
+      &:not(.t3-form-element-toplevel) {
+        margin-bottom: 1em;
+        padding-bottom: 1px;
+        outline: 1px solid #dddddd;
+        outline-offset: -1px;
+      }
+      .sortable-hover {
+        outline-color: darken(@panel-default-heading-bg, 40%);
+      }
+      .t3-form-form-composit-element-selected {
+        outline-color: @brand-primary;
+      }
+    }
+    .t3-form-element-composit.sortable-hover > .ui-sortable-handle,
+    .ui-sortable-handle:hover {
+      border-color: darken(@panel-default-heading-bg, 40%);
+      .t3-form-icon-container {
+        background-color: darken(@panel-default-heading-bg, 40%);
+        path {
+          fill: #fff;
+        }
+      }
+    }
+    .ui-sortable {
+      fieldset {
+        position: relative;
+        min-height: 130px;
+        padding-top: 5em;
+        legend {
+          position: absolute;
+          top: 1em;
+          display: inline-block;
+          width: 95%;
+        }
+      }
+    }
+    .ui-sortable-handle {
+      overflow: hidden;
+      position: relative;
+      height: @stage-abstract-element-height;
+      margin-bottom: 1em;
+      border: 1px solid @panel-default-heading-bg;
+      background-color: #fff;
+
+      &:hover {
+        .t3-form-validator-list {
+          right: 0;
+          transition: right @stage-validation-transition-time-in;
+        }
+        .t3-form-element-info .element-content {
+          span, div {
+            color: @gray-dark;
+          }
+        }
+        .t3-form-validator-info .t3-form-icon {
+          margin-right: (@stage-validation-list-width - 25);
+          transition: margin @stage-validation-transition-time-in;
+        }
+      }
+      &:has (.ui-sortable-handle:hover) {
+        border-color: transparent;
+      }
+      span {
+        color: @gray-dark;
+      }
+    }
+    .ui-state-disabled {
+      cursor: auto;
+      &:hover {
+        background: none;
+      }
+    }
+    .ui-sortable-placeholder {
+      margin-bottom: 1em;
+    }
+    .t3-form-icon-container {
+      float: left;
+      width: @stage-icon-container-width;
+      height: 100%;
+      padding: 1em;
+      cursor: move;
+      background-color: @panel-default-heading-bg;
+      .t3-form-icon {
+        height: 100%;
+      }
+    }
+    .t3-form-form-element-body {
+      height: 100%;
+    }
+    .t3-form-element-info {
+      position: relative;
+      float: left;
+      width: 55%;
+      height: 100%;
+      padding-left: 1em;
+      .fade-out-gradient-effect-bottom (#fff, 0.8em, 1em);
+      .element-label-container {
+        float: left;
+        position: relative;
+        width: 45%;
+        height: 100%;
+        .element-label {
+          overflow: hidden;
+          position: absolute;
+          top: 50%;
+          width: 100%;
+          text-overflow: ellipsis;
+          transform: translateY(-50%);
+        }
+      }
+      .element-content {
+        padding-top: 1em;
+        white-space: nowrap;
+        font-size: 0.8em;
+        span, div {
+          color: @panel-default-heading-bg;
+        }
+      }
+    }
+    .t3-form-validator-info {
+      position: relative;
+      overflow: hidden;
+      float: right;
+      height: 100%;
+      .t3-form-icon {
+        height: 100%;
+        z-index: 1;
+        margin-left: 1em;
+        transition: margin @stage-validation-transition-time-out;
+        filter: grayscale(100%);
+      }
+      .t3-form-validator-list {
+        .fade-out-gradient-effect-bottom(@panel-default-heading-bg, 1em, 1em);
+        position: absolute;
+        top: 0;
+        right: -@stage-validation-list-width;
+        width: @stage-validation-list-width;
+        height: 100%;
+        padding: 1em 1em 1em (@stage-validation-list-width - 65);
+        font-size: 0.8em;
+        transition: right @stage-validation-transition-time-out;
+        background-color: @panel-default-heading-bg;
+      }
+      .validator-label {
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+        color: @gray-dark;
+      }
+    }
+    #t3-form-stage .t3-form-form-element-selected {
+      position: relative;
+      padding-top: @stage-abstract-element-toolbar-height;
+      height: @stage-abstract-element-height + @stage-abstract-element-toolbar-height;
+      border: none;
+
+      .t3-form-form-element-body {
+        border: 1px solid @brand-primary;
+      }
+      .t3-form-icon-container {
+        background-color: @brand-primary;
+      }
+      .t3-form-element-info .element-content {
+        span, div {
+          color: @gray-dark;
+        }
+      }
+      .t3-form-validator-list {
+        @validation-list-background: lighten(@brand-info, 30%);
+        right: 0;
+        transition: right @stage-validation-transition-time-in;
+        background-color: @validation-list-background;
+        &:before {
+          background-color: @validation-list-background;
+        }
+        &:after {
+          background: linear-gradient(to bottom, rgba(red(@validation-list-background), green(@validation-list-background), blue(@validation-list-background), 0) 0%, @validation-list-background 100%);
+        }
+      }
+      .t3-form-validator-info .t3-form-icon {
+        margin-right: (@stage-validation-list-width - 25);
+        filter: none;
+      }
+      .btn-toolbar-container {
+        position: absolute;
+        top: 0;
+        right: 0;
+        width: 100%;
+        height: @stage-abstract-element-toolbar-height;
+        border: 1px solid @brand-primary;
+        background-color: @brand-primary;
+        padding-right: 0.7em;
+        padding-top: 0.4em;
+        &:before, &:after {
+          position: absolute;
+          top: 0;
+          display: block;
+          width: 1px;
+          height: 100%;
+          content: ' ';
+          background-color: @brand-primary;
+        }
+        &:before {
+          left: -1px;
+        }
+        &:after {
+          right: -1px;
+        }
+        .dropdown-menu {
+          left: auto;
+          left: initial;
+          min-width: initial;
+          right: 0;
+          padding-left: 0;
+          padding-right: 0;
+          background-color: darken(@brand-primary, 10%);
+          > li a:hover {
+            background-color: darken(@brand-primary, 5%);
+          }
+        }
+        .caret {
+          color: @brand-primary;
+        }
+        .t3-form-dropdown-buttons {
+          .icon {
+            margin-right: 0.5em;
+          }
+        }
+        .btn-toolbar {
+          float: right;
+          .selected-button-style-primary;
+        }
+      }
+      .meta-label {
+        display: inline-block;
+        top: 1em;
+        left: 5em;
+        bottom: auto;
+        font-size: 0.9em;
+        color: #fff;
+        span {
+          color: #fff;
+        }
+      }
+    }
+    .panel.t3-form-form-stage-selected {
+      border-color: @brand-primary;
+      > .panel-heading {
+        background-color: @brand-primary;
+        border-color: @brand-primary;
+        color: #fff;
+        .selected-button-style-primary;
+      }
+    }
+  }
 
-#fake-form .formwizard-element.active,
-#fake-form .formwizard-element.hidden.active {
-  background-color: #EAF7FF;
-  border: 1px solid #C5DBE6;
-}
+  // Preview
+  &.t3-form-stage-viewmode-preview {
+    input[type="text"], input[type="date"], input[type="password"], textarea, select {
+      color: #000;
+      background-color: lighten(@panel-default-heading-bg, 3%);
+    }
+    ::placeholder {
+      color: @gray;
+      font-style: italic;
+    }
+    input[type="date"] {
+      display: block;
+      width: 100%;
+      height: 32px;
+      padding: 0.6em;
+      font-size: 12px;
+      line-height: 1.5;
+      background-image: none;
+      border: 1px solid @module-docheader-border;
+      border-radius: 2px;
+      box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+      transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+    }
+    select[multiple="multiple"] {
+      height: auto;
+      min-height: 32px;
+    }
+    textarea {
+      min-height: 100px;
+    }
+    legend.t3-form-form-element-selected {
+      border-color: @module-docheader-border;
+    }
+    .form-navigation {
+      .btn-group {
+        span, button {
+          display: inline-block;
+          margin-right: 1em;
+        }
+      }
+    }
+    .preview-table-first-col {
+      width: 30%;
+    }
+    .t3-form-element-preview {
+      position: relative;
+      display: inline-block;
+      width: 100%;
+    }
+    .t3-form-new-element-container {
+      display: none;
+    }
+    .t3-form-element-toplevel > form > .tooltip {
+        top: 100px !important;
+    }
+  }
 
-#fake-form .formwizard-element.hidden {
-  min-height: 1em;
-  background-color: transparent;
-  border: 1px dotted #C5DBE6;
+  #t3-form-stage {
+    margin-bottom: 0;
+    padding-top: 0.5em;
+    > ol, > ol > li > ol {
+      padding-left: 0;
+      padding-right: 0;
+    }
+    .t3-form-element-toplevel {
+      > .t3-form-form-element-selected {
+        height: auto;
+        padding-top: 0;
+      }
+      > .t3-form-form-element-selected .btn-toolbar-container {
+        display: none;
+      }
+    }
+  }
 }
 
-/* toolbar on each element */
-#fake-form .formwizard-element div.buttongroup {
+.meta-label {
+  z-index: 1;
   position: absolute;
-  right: 0;
-  top: -35px;
+  bottom: 1em;
+  left: 5.5em;
   display: none;
-  z-index: 1;
-  padding: 4px 3px 12px;
-  background-image: url("../Images/tooltip.png");
+  color: @brand-primary;
+  line-height: 1.6;
+  font-size: 0.8em;
+  .ui-sortable-handle:hover > & {
+    display: inline-block;
+  }
 }
 
-#fake-form .formwizard-element.hover > div.buttongroup,
-#fake-form .formwizard-element.active > div.buttongroup {
-  display: block;
+.ui-sortable-placeholder,
+.t3-form-element-composit.ui-sortable-placeholder {
+  background-color: #fff !important;
+  border: none !important;
+  outline: 1px dashed lighten(@brand-success, 30%) !important;
+  outline-offset: -2px !important;
+  visibility: visible !important;
 }
 
-#fake-form .formwizard-element div.buttongroup button {
-  width: 16px;
-  height: 16px;
-  background-color: transparent;
-  border: 0 solid transparent;
+//
+// Icons
+//
+.t3-form-icon {
+  margin-right: 1em;
 }
 
-#fake-form .formwizard-element div.buttongroup span {
-  margin: 0 3px;
+//
+// Validation Errors
+//
+.t3-form-validation-child-has-error {
+  color: @brand-danger;
 }
 
-#fake-form .formwizard-element div.buttongroup span.x-btn-over {
-  background-color: transparent;
-  background-image: none;
+.t3-form-validation-errors {
+  #t3-form-navigation-component &,
+  #t3-form-stage-container & {
+    position: relative;
+    color: @brand-danger;
+    &:before {
+      z-index: 1;
+      position: absolute;
+      display: inline-block;
+      width: 15px;
+      height: 15px;
+      font-family: FontAwesome;
+      vertical-align: middle;
+      border-radius: 50%;
+      font-size: 1em;
+      line-height: 1.4;
+      text-align: center;
+      background: none;
+    }
+  }
+  #t3-form-navigation-component & {
+    &:hover:before,
+    &.t3-form-form-element-selected:before {
+      left: 2.4em;
+    }
+    &:before {
+      margin-top: 0.2em;
+      color: #fff;
+      font-size: 10px;
+      font-weight: 800;
+      content: "\f12a";
+      background-color: @brand-danger;
+    }
+  }
+  &#t3-form-navigation-component-tree-root:before {
+    left: -2em !important;
+    margin-top: 0.1em;
+  }
+  #t3-form-stage-container &.ui-sortable-handle {
+    border-color: @brand-danger;
+    &:before {
+      left: 4.5em;
+      margin-top: 1.9em;
+      content:  "\f071";
+    }
+    .element-label {
+      padding-left: 1.5em;
+    }
+  }
+  #t3-form-inspector-panels .t3-form-collection-element & {
+    display: inline-block;
+    color: #fff;
+    font-size: 0.8em;
+    font-weight: 700;
+    background-color: @brand-danger;
+    margin-top: 0.5em;
+    padding: 0.1em 0.5em;
+    border-radius: 2px;
+  }
+  #t3-form-inspector-panels &.t3-form-collection-element {
+    border-color: @brand-danger;
+
+    h4 {
+      border-color: @brand-danger;
+      background-color: @brand-danger;
+      color: #fff;
+      path {
+        fill: #fff;
+      }
+    }
+    .t3-form-collection-element-remove-button {
+      background: #fff;
+      border-color: transparent;
+      path {
+        fill: @brand-danger;
+      }
+    }
+  }
 }
 
-#fake-form .formwizard-element button.t3-icon-edit-delete {
-  background-image: url('../../../../core/Resources/Public/Icons/T3Icons/actions/actions-delete.svg');
+//
+// Loading Editor Spinner
+//
+.form-editor-loading-spinner {
+  width: 150px;
+  margin: 5em auto 0;
+  text-align: center;
 }
 
-#fake-form .formwizard-element button.t3-icon-document-open {
-  background-image: url('../../../../core/Resources/Public/Icons/T3Icons/actions/actions-open.svg');
+//
+// jQuery nestedSortable
+//
+.ui-sortable-handle {
+  cursor: pointer;
 }
 
-@media only screen and (max-width:615px) {
-  .tab-content fieldset.form-section ol#formwizard-right{
-    left:0 !important;
+//
+// Module
+//
+.module[data-module-name="web_FormFormbuilder_FormEditor"] {
+  overflow: hidden;
+  .module-body, div[data-identifier="moduleWrapper"] {
+    height: 100%;
+  }
+  .module-body {
+    padding-bottom: 0.5em;
+  }
+  .module-docheader-bar-column-left {
+    button {
+      &, &:focus, &:active {
+        outline: 0;
+        outline-color: initial;
+        outline-style: initial;
+        outline-width: 0px;
+      }
+    }
+    .btn-group {
+      margin-left: 25px;
+    }
   }
 }
+
+.t3-form-element-new-page-button {
+  position: absolute;
+  left: 0.5em;
+}
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 784ca9ab3632bbedfa8600ab09125d941c918518..7c587acd4c1b54a8dbd999456ea6fa5870e9c827 100644
--- a/composer.json
+++ b/composer.json
@@ -40,6 +40,7 @@
 		"swiftmailer/swiftmailer": "~5.4.3",
 		"symfony/console": "^2.7 || ^3.0",
 		"symfony/finder": "^2.7 || ^3.0",
+		"symfony/yaml": "^2.7 || ^3.0",
 		"doctrine/instantiator": "~1.0.4",
 		"typo3/class-alias-loader": "^1.0",
 		"typo3/cms-composer-installers": "^1.2.8",
diff --git a/composer.lock b/composer.lock
index 51dff215a913d6658830f899ec1383c080bf3447..fe9516c43d57fb141dc3a6869ac30638492d252e 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,8 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "hash": "90479fd517e730794243c516ef4ba9ae",
-    "content-hash": "9ac01b16aca6a55472ecf320b6dacf31",
+    "hash": "9cc1058ed137d0775741d7c5701e77a1",
+    "content-hash": "2749660dc0a03d1b473808cf28c9cf10",
     "packages": [
         {
             "name": "cogpowered/finediff",
@@ -1119,6 +1119,55 @@
             ],
             "time": "2016-05-18 14:26:46"
         },
+        {
+            "name": "symfony/yaml",
+            "version": "v3.1.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/yaml.git",
+                "reference": "7ff51b06c6c3d5cc6686df69004a42c69df09e27"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/7ff51b06c6c3d5cc6686df69004a42c69df09e27",
+                "reference": "7ff51b06c6c3d5cc6686df69004a42c69df09e27",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Yaml\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Yaml Component",
+            "homepage": "https://symfony.com",
+            "time": "2016-10-24 18:41:13"
+        },
         {
             "name": "typo3/class-alias-loader",
             "version": "1.0.0",
@@ -3234,55 +3283,6 @@
             "homepage": "https://symfony.com",
             "time": "2016-06-29 05:41:56"
         },
-        {
-            "name": "symfony/yaml",
-            "version": "v3.1.6",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/yaml.git",
-                "reference": "7ff51b06c6c3d5cc6686df69004a42c69df09e27"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/yaml/zipball/7ff51b06c6c3d5cc6686df69004a42c69df09e27",
-                "reference": "7ff51b06c6c3d5cc6686df69004a42c69df09e27",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.5.9"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.1-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Yaml\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Yaml Component",
-            "homepage": "https://symfony.com",
-            "time": "2016-10-24 18:41:13"
-        },
         {
             "name": "webmozart/assert",
             "version": "1.1.0",
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-77910-EXTform-IntroduceNewFormFramework.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-77910-EXTform-IntroduceNewFormFramework.rst
new file mode 100644
index 0000000000000000000000000000000000000000..db99783b331ef18ea90391ed43e92eefebc3f9e5
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-77910-EXTform-IntroduceNewFormFramework.rst
@@ -0,0 +1,54 @@
+.. include:: ../../Includes.txt
+
+=========================================================
+Feature: #77910 - EXT:form - introduce new form framework
+=========================================================
+
+See :issue:`77910`
+
+Description
+===========
+
+A flexible framework for building forms is integrated. It replaces the legacy 'form wizard' based on ExtJS and the
+depending frontend rendering system.
+
+The new backend 'form editor' relies on vanilla JS and jQuery. Different JS patterns have been applied to ensure
+a modern architecture, high flexibility and extensibility.
+
+A new backend module lists all existing forms and allows the creation of new ones. The 'mailform' content element
+is reworked. It lists available forms and enables the backend editor to override certain settings, e.g. 'finisher'
+settings (formerly known as 'postProcessors').
+
+Till now it was not possible to customize and extend the 'form editor'. To allow the registration of new
+finishers, validators and pre-defined form elements a lot of architectural changes were needed. After a long
+conceptional phase the team decided to remove the former code base, backport the 'form' package of the Flow
+project and improve the given ideas and concepts. The result is a new form extension. A lot of code received
+major improvements and tons of additional features have been integrated.
+
+The list of features is long and impressive. The documentation will explain the ideas, concept and architecture
+as well as the functionality in detail. The following list names some of them:
+
+* YAML as configuration and description language including inheritances and overrides.
+* File based configuration.
+* All JavaScript components of the form wizard (and the wizard itself) can be replaced or extended.
+* Own PHP renderer for form and/ or form elements possible.
+* Create entire forms via API.
+* Create conditions for form elements and validators programmatically.
+* Create 'prototypes' and use them as boilerplate.
+* Create new form elements and use them in the wizard.
+* Uploads are handled as FAL objects.
+* Ships bunch of built-in finishers, like email, redirect, save to database.
+* Create own finishers. Override thos in the content element.
+* Create and apply own validators.
+* Multi language support.
+* Multi step support.
+* Multiple forms per page.
+* Built-in spam protection (honeypot).
+
+
+Impact
+======
+
+Happy little wizard.
+
+.. index:: Frontend, PHP-API, JavaScript, ext:form
\ No newline at end of file
diff --git a/typo3/sysext/form/Classes/ContentObject/FormContentObject.php b/typo3/sysext/form/Classes/ContentObject/FormContentObject.php
deleted file mode 100644
index e2176de9c1a7624b24658c5f606772c3f26f38f9..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/ContentObject/FormContentObject.php
+++ /dev/null
@@ -1,124 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\ContentObject;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
-use TYPO3\CMS\Core\Utility\ArrayUtility;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Form\Domain\Model\Configuration;
-use TYPO3\CMS\Frontend\ContentObject\AbstractContentObject;
-use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
-
-/**
- * FORM cObject, a wrapper to allow to use 10 = FORM in TypoScript
- * which actually executes the Extbase plugin (marked as non-cached)
- */
-class FormContentObject extends AbstractContentObject
-{
-    /**
-     * Renders the application defined cObject FORM
-     *
-     * The Extbase plugin "Form" is initialized. At this time, the
-     * controller "Frontend" action "show" does the rest.
-     *
-     * @param array $conf TS configuration for this cObject
-     * @return string HTML output
-     * @throws \InvalidArgumentException
-     */
-    public function render($conf = [])
-    {
-        $mergedTypoScript = null;
-        // If the FORM configuration is retrieved from the database
-        // all TypoScript interpretation will be disabled for security.
-        if ($this->cObj->data['CType'] === 'mailform') {
-            // If the FORM configuration is retrieved from the database
-            // and a predefined form is selected then the TypoScript
-            // interpretation is allowed.
-            $renderPredefinedForm = false;
-            $predefinedFormIdentifier = null;
-            if (!empty($this->cObj->data['tx_form_predefinedform'])) {
-                $predefinedFormIdentifier = $this->cObj->data['tx_form_predefinedform'];
-                if (isset($this->getTypoScriptFrontendController()->tmpl->setup['plugin.']['tx_form.']['predefinedForms.'][$predefinedFormIdentifier . '.'])) {
-                    $renderPredefinedForm = true;
-                } else {
-                    throw new \InvalidArgumentException('No FORM configuration for identifier "' . $predefinedFormIdentifier . '" available.', 1466769483);
-                }
-            }
-
-            if ($renderPredefinedForm && $predefinedFormIdentifier) {
-                $mergedTypoScript = $this->getTypoScriptFrontendController()->tmpl->setup['plugin.']['tx_form.']['predefinedForms.'][$predefinedFormIdentifier . '.'];
-                ArrayUtility::mergeRecursiveWithOverrule($mergedTypoScript, $conf);
-            } else {
-                $bodytext = $this->cObj->data['bodytext'];
-                /** @var $typoScriptParser TypoScriptParser */
-                $typoScriptParser = GeneralUtility::makeInstance(TypoScriptParser::class);
-                $typoScriptParser->parse($bodytext);
-                $mergedTypoScript = (array)$typoScriptParser->setup;
-                ArrayUtility::mergeRecursiveWithOverrule($mergedTypoScript, $conf);
-                // Disables TypoScript interpretation since TypoScript is handled that could contain insecure settings:
-                $mergedTypoScript[Configuration::DISABLE_CONTENT_ELEMENT_RENDERING] = true;
-            }
-        }
-
-        // make sure the extbase plugin is marked as Uncached
-        $content = $this->prepareNonCacheableUserFunction(is_array($mergedTypoScript) ? $mergedTypoScript : $conf);
-
-        // Only apply stdWrap to TypoScript that was NOT created by the wizard:
-        if (isset($conf['stdWrap.'])) {
-            $content = $this->cObj->stdWrap($content, $conf['stdWrap.']);
-        }
-        return $content;
-    }
-
-    /**
-     * Set up the extbase plugin to be a non-cacheable user function
-     *
-     * @param array $typoScript
-     * @return string the content as placeholder for USER_INT code
-     */
-    protected function prepareNonCacheableUserFunction($typoScript)
-    {
-        $configuration = [
-            'userFunc' => 'TYPO3\\CMS\\Extbase\\Core\\Bootstrap->run',
-            'pluginName' => 'Form',
-            'extensionName' => 'Form',
-            'vendorName' => 'TYPO3\\CMS',
-            'controller' => 'Frontend',
-            'action' => 'show',
-            'settings' => ['typoscript' => $typoScript],
-            'persistence' => [],
-            'view' => [],
-        ];
-
-        $this->cObj->setUserObjectType(ContentObjectRenderer::OBJECTTYPE_USER_INT);
-        $substKey = 'INT_SCRIPT.' . $this->getTypoScriptFrontendController()->uniqueHash();
-        $content = '<!--' . $substKey . '-->';
-        $this->getTypoScriptFrontendController()->config['INTincScript'][$substKey] = [
-            'conf' => $configuration,
-            'cObj' => serialize($this->cObj),
-            'type' => 'FUNC'
-        ];
-        $this->cObj->setUserObjectType(false);
-        return $content;
-    }
-
-    /**
-     * @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
-     */
-    protected function getTypoScriptFrontendController()
-    {
-        return $GLOBALS['TSFE'];
-    }
-}
diff --git a/typo3/sysext/form/Classes/Controller/AbstractBackendController.php b/typo3/sysext/form/Classes/Controller/AbstractBackendController.php
new file mode 100644
index 0000000000000000000000000000000000000000..0f028e4982f70080295e4f900dee480996b930ca
--- /dev/null
+++ b/typo3/sysext/form/Classes/Controller/AbstractBackendController.php
@@ -0,0 +1,91 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Controller;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\PathUtility;
+use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
+use TYPO3\CMS\Form\Mvc\Configuration\ConfigurationManagerInterface;
+
+/**
+ * The abstract form backend controller
+ *
+ * Scope: backend
+ */
+abstract class AbstractBackendController extends ActionController
+{
+
+    /**
+     * @var array
+     */
+    protected $formSettings;
+
+    /**
+     * @var \TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface
+     */
+    protected $formPersistenceManager;
+
+    /**
+     * @param \TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface $formPersistenceManager
+     * @return void
+     * @internal
+     */
+    public function injectFormPersistenceManager(\TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface $formPersistenceManager)
+    {
+        $this->formPersistenceManager = $formPersistenceManager;
+    }
+
+    /**
+     * @internal
+     */
+    public function initializeObject()
+    {
+        $this->formSettings = $this->objectManager->get(ConfigurationManagerInterface::class)
+            ->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_YAML_SETTINGS, 'form');
+    }
+
+    /**
+     * Convert arrays with EXT: resource paths to web paths
+     *
+     * Input:
+     * [
+     *   100 => 'EXT:form/Resources/Public/Css/form.css'
+     * ]
+     *
+     * Output:
+     *
+     * [
+     *   0 => 'typo3/sysext/form/Resources/Public/Css/form.css'
+     * ]
+     *
+     * @param array $resourcePaths
+     * @return array
+     */
+    protected function resolveResourcePaths(array $resourcePaths): array
+    {
+        $return = [];
+        foreach ($resourcePaths as $resourcePath) {
+            $fullResourcePath = GeneralUtility::getFileAbsFileName($resourcePath);
+            $resourcePath = PathUtility::getAbsoluteWebPath($fullResourcePath);
+            if (empty($resourcePath)) {
+                continue;
+            }
+            $return[] = $resourcePath;
+        }
+
+        return $return;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Controller/FormEditorController.php b/typo3/sysext/form/Classes/Controller/FormEditorController.php
new file mode 100644
index 0000000000000000000000000000000000000000..756015cd4019a4ef816a1f9ef2db05d95e955cdd
--- /dev/null
+++ b/typo3/sysext/form/Classes/Controller/FormEditorController.php
@@ -0,0 +1,445 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Controller;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Backend\Template\Components\ButtonBar;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Backend\View\BackendTemplateView;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Imaging\Icon;
+use TYPO3\CMS\Core\Utility\ArrayUtility as CoreArrayUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Fluid\View\StandaloneView;
+use TYPO3\CMS\Form\Domain\Configuration\ConfigurationService;
+use TYPO3\CMS\Form\Domain\Exception\RenderingException;
+use TYPO3\CMS\Form\Domain\Factory\ArrayFormFactory;
+use TYPO3\CMS\Form\Mvc\Persistence\Exception\PersistenceManagerException;
+use TYPO3\CMS\Form\Service\TranslationService;
+use TYPO3\CMS\Form\Utility\ArrayUtility;
+use TYPO3\CMS\Lang\LanguageService;
+
+/**
+ * The form editor controller
+ *
+ * Scope: backend
+ */
+class FormEditorController extends AbstractBackendController
+{
+
+    /**
+     * Default View Container
+     *
+     * @var BackendTemplateView
+     */
+    protected $defaultViewObjectName = BackendTemplateView::class;
+
+    /**
+     * @var array
+     */
+    protected $prototypeConfiguration;
+
+    /**
+     * Displays the form editor
+     *
+     * @param string $formPersistenceIdentifier
+     * @param string $prototypeName
+     * @return void
+     * @throws PersistenceManagerException
+     * @internal
+     */
+    public function indexAction(string $formPersistenceIdentifier, string $prototypeName = null)
+    {
+        $this->registerDocheaderButtons();
+        $this->view->getModuleTemplate()->setModuleName($this->request->getPluginName() . '_' . $this->request->getControllerName());
+        $this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue());
+
+        if (
+            strpos($formPersistenceIdentifier, 'EXT:') === 0
+            && !$this->formSettings['persistenceManager']['allowSaveToExtensionPaths']
+        ) {
+            throw new PersistenceManagerException('Edit a extension formDefinition is not allowed.', 1478265661);
+        }
+
+        $formDefinition = $this->formPersistenceManager->load($formPersistenceIdentifier);
+        $formDefinition = ArrayUtility::stripTagsFromValuesRecursive($formDefinition);
+        if (empty($prototypeName)) {
+            $prototypeName = isset($formDefinition['prototypeName']) ? $formDefinition['prototypeName'] : 'standard';
+        }
+        $formDefinition['prototypeName'] = $prototypeName;
+
+        $configurationService = $this->objectManager->get(ConfigurationService::class);
+        $this->prototypeConfiguration = $configurationService->getPrototypeConfiguration($prototypeName);
+
+        $formEditorDefinitions = $this->getFormEditorDefinitions();
+
+        $formEditorAppInitialData = [
+            'formEditorDefinitions' => $formEditorDefinitions,
+            'formDefinition' => $formDefinition,
+            'formPersistenceIdentifier' => $formPersistenceIdentifier,
+            'prototypeName' => $prototypeName,
+            'endpoints' => [
+                'formPageRenderer' => $this->controllerContext->getUriBuilder()->uriFor('renderFormPage'),
+                'saveForm' => $this->controllerContext->getUriBuilder()->uriFor('saveForm')
+            ],
+            'additionalViewModelModules' => $this->prototypeConfiguration['formEditor']['dynamicRequireJsModules']['additionalViewModelModules'],
+            'maximumUndoSteps' => $this->prototypeConfiguration['formEditor']['maximumUndoSteps'],
+        ];
+
+        $this->view->assign('formEditorAppInitialData', json_encode($formEditorAppInitialData));
+        $this->view->assign('stylesheets', $this->resolveResourcePaths($this->prototypeConfiguration['formEditor']['stylesheets']));
+        $this->view->assign('formEditorTemplates', $this->renderFormEditorTemplates(
+            $this->prototypeConfiguration['formEditor']['formEditorTemplates'],
+            $formEditorDefinitions
+        ));
+        $this->view->assign('dynamicRequireJsModules', $this->prototypeConfiguration['formEditor']['dynamicRequireJsModules']);
+
+        $popupWindowWidth  = 700;
+        $popupWindowHeight = 750;
+        $popupWindowSize = ($this->getBackendUser()->getTSConfigVal('options.popupWindowSize'))
+            ? trim($this->getBackendUser()->getTSConfigVal('options.popupWindowSize'))
+            : null;
+        if (!empty($popupWindowSize)) {
+            list($popupWindowWidth, $popupWindowHeight) = GeneralUtility::intExplode('x', $popupWindowSize);
+        }
+
+        $addInlineSettings = [
+            'FormEditor' => [
+                'typo3WinBrowserUrl' => BackendUtility::getModuleUrl('wizard_element_browser'),
+            ],
+            'Popup' => [
+                'PopupWindow' => [
+                    'width' => $popupWindowWidth,
+                    'height' => $popupWindowHeight
+                ],
+            ]
+        ];
+
+        CoreArrayUtility::mergeRecursiveWithOverrule(
+            $addInlineSettings,
+            $this->prototypeConfiguration['formEditor']['addInlineSettings']
+        );
+        $this->view->assign('addInlineSettings', $addInlineSettings);
+    }
+
+    /**
+     * Save a formDefinition which was build by the form editor.
+     *
+     * @param string $formPersistenceIdentifier
+     * @param array $formDefinition
+     * @return string
+     * @internal
+     */
+    public function saveFormAction(string $formPersistenceIdentifier, array $formDefinition): string
+    {
+        $formDefinition = ArrayUtility::stripTagsFromValuesRecursive($formDefinition);
+        $formDefinition = $this->convertJsonArrayToAssociativeArray($formDefinition);
+        $this->formPersistenceManager->save($formPersistenceIdentifier, $formDefinition);
+        return '';
+    }
+
+    /**
+     * Render a page from the formDefinition which was build by the form editor.
+     * Use the frontend rendering and set the form framework to preview mode.
+     *
+     * @param array $formDefinition
+     * @param int $pageIndex
+     * @param string $prototypeName
+     * @return string
+     * @internal
+     */
+    public function renderFormPageAction(array $formDefinition, int $pageIndex, string $prototypeName = null): string
+    {
+        $formDefinition = ArrayUtility::stripTagsFromValuesRecursive($formDefinition);
+        $formDefinition = $this->convertJsonArrayToAssociativeArray($formDefinition);
+        if (empty($prototypeName)) {
+            $prototypeName = isset($formDefinition['prototypeName']) ? $formDefinition['prototypeName'] : 'standard';
+        }
+
+        $formFactory = $this->objectManager->get(ArrayFormFactory::class);
+        $formDefinition = $formFactory->build($formDefinition, $prototypeName);
+        $formDefinition->setRenderingOption('previewMode', true);
+        $form = $formDefinition->bind($this->request, $this->response);
+        $form->overrideCurrentPage($pageIndex);
+        return $form->render();
+    }
+
+    /**
+     * Prepare the formElements.*.formEditor section from the yaml settings.
+     * Sort all formElements into groups and add additional data.
+     *
+     * @param array $formElementsDefinition
+     * @return array
+     */
+    protected function getInsertRenderablesPanelConfiguration(array $formElementsDefinition): array
+    {
+        $formElementGroups = isset($this->prototypeConfiguration['formEditor']['formElementGroups']) ? $this->prototypeConfiguration['formEditor']['formElementGroups'] : [];
+        $formElementsByGroup = [];
+
+        foreach ($formElementsDefinition as $formElementName => $formElementConfiguration) {
+            if (!isset($formElementConfiguration['group'])) {
+                continue;
+            }
+            if (!isset($formElementsByGroup[$formElementConfiguration['group']])) {
+                $formElementsByGroup[$formElementConfiguration['group']] = [];
+            }
+
+            $formElementsByGroup[$formElementConfiguration['group']][] = [
+                'key' => $formElementName,
+                'cssKey' => preg_replace('/[^a-z0-9]/', '-', strtolower($formElementName)),
+                'label' => TranslationService::getInstance()->translate(
+                    $formElementConfiguration['label'],
+                    null,
+                    $this->prototypeConfiguration['formEditor']['translationFile'],
+                    null,
+                    $formElementConfiguration['label']
+                ),
+                'sorting' => $formElementConfiguration['groupSorting'],
+                'iconIdentifier' => $formElementConfiguration['iconIdentifier'],
+            ];
+        }
+
+        $formGroups = [];
+        foreach ($formElementGroups as $groupName => $groupConfiguration) {
+            if (!isset($formElementsByGroup[$groupName])) {
+                continue;
+            }
+
+            usort($formElementsByGroup[$groupName], function ($a, $b) {
+                return $a['sorting'] - $b['sorting'];
+            });
+            unset($formElementsByGroup[$groupName]['sorting']);
+
+            $formGroups[] = [
+                'key' => $groupName,
+                'elements' => $formElementsByGroup[$groupName],
+                'label' => TranslationService::getInstance()->translate(
+                    $groupConfiguration['label'],
+                    null,
+                    $this->prototypeConfiguration['formEditor']['translationFile'],
+                    null,
+                    $groupConfiguration['label']
+                ),
+            ];
+        }
+
+        return $formGroups;
+    }
+
+    /**
+     * Reduce the Yaml settings by the 'formEditor' keyword.
+     *
+     * @return array
+     */
+    protected function getFormEditorDefinitions(): array
+    {
+        $formEditorDefinitions = [];
+        foreach ([$this->prototypeConfiguration, $this->prototypeConfiguration['formEditor']] as $configuration) {
+            foreach ($configuration as $firstLevelItemKey => $firstLevelItemValue) {
+                if (substr($firstLevelItemKey, -10) !== 'Definition') {
+                    continue;
+                }
+                $reducedKey = substr($firstLevelItemKey, 0, -10);
+                foreach ($configuration[$firstLevelItemKey] as $formEditorDefinitionKey => $formEditorDefinitionValue) {
+                    if (isset($formEditorDefinitionValue['formEditor'])) {
+                        $formEditorDefinitionValue = array_intersect_key($formEditorDefinitionValue, array_flip(['formEditor']));
+                        $formEditorDefinitions[$reducedKey][$formEditorDefinitionKey] = $formEditorDefinitionValue['formEditor'];
+                    } else {
+                        $formEditorDefinitions[$reducedKey][$formEditorDefinitionKey] = $formEditorDefinitionValue;
+                    }
+                }
+            }
+        }
+        $formEditorDefinitions = ArrayUtility::reIndexNumericArrayKeysRecursive($formEditorDefinitions);
+        $formEditorDefinitions = TranslationService::getInstance()->translateValuesRecursive(
+            $formEditorDefinitions,
+            $this->prototypeConfiguration['formEditor']['translationFile']
+        );
+        return $formEditorDefinitions;
+    }
+
+    /**
+     * Registers the Icons into the docheader
+     *
+     * @throws \InvalidArgumentException
+     */
+    protected function registerDocheaderButtons()
+    {
+        /** @var ButtonBar $buttonBar */
+        $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
+        $getVars = $this->request->getArguments();
+
+        if (isset($getVars['action']) && $getVars['action'] === 'index') {
+            $newPageButton = $buttonBar->makeInputButton()
+                ->setDataAttributes(['action' => 'formeditor-new-page', 'identifier' => 'headerNewPage'])
+                ->setTitle($this->getLanguageService()->sL('LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.new_page_button'))
+                ->setName('formeditor-new-page')
+                ->setValue('new-page')
+                ->setClasses('t3-form-element-new-page-button hidden')
+                ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-page-new', Icon::SIZE_SMALL));
+
+            $closeButton = $buttonBar->makeLinkButton()
+                ->setDataAttributes(['identifier' => 'closeButton'])
+                ->setHref(BackendUtility::getModuleUrl('web_FormFormbuilder'))
+                ->setClasses('t3-form-element-close-form-button hidden')
+                ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.closeDoc'))
+                ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-document-close', Icon::SIZE_SMALL));
+
+            $saveButton = $buttonBar->makeInputButton()
+                ->setDataAttributes(['identifier' => 'saveButton'])
+                ->setTitle($this->getLanguageService()->sL('LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.save_button'))
+                ->setName('formeditor-save-form')
+                ->setValue('save')
+                ->setClasses('t3-form-element-save-form-button hidden')
+                ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-document-save', Icon::SIZE_SMALL))
+                ->setShowLabelText(true);
+
+            $undoButton = $buttonBar->makeInputButton()
+                ->setDataAttributes(['identifier' => 'undoButton'])
+                ->setTitle($this->getLanguageService()->sL('LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.undo_button'))
+                ->setName('formeditor-undo-form')
+                ->setValue('undo')
+                ->setClasses('t3-form-element-undo-form-button hidden disabled')
+                ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
+
+            $redoButton = $buttonBar->makeInputButton()
+                ->setDataAttributes(['identifier' => 'redoButton'])
+                ->setTitle($this->getLanguageService()->sL('LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.redo_button'))
+                ->setName('formeditor-redo-form')
+                ->setValue('redo')
+                ->setClasses('t3-form-element-redo-form-button hidden disabled')
+                ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-forward', Icon::SIZE_SMALL));
+
+            $buttonBar->addButton($newPageButton, ButtonBar::BUTTON_POSITION_LEFT, 1);
+            $buttonBar->addButton($closeButton, ButtonBar::BUTTON_POSITION_LEFT, 2);
+            $buttonBar->addButton($saveButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
+            $buttonBar->addButton($undoButton, ButtonBar::BUTTON_POSITION_LEFT, 4);
+            $buttonBar->addButton($redoButton, ButtonBar::BUTTON_POSITION_LEFT, 4);
+        }
+    }
+
+    /**
+     * Some data which is build by the form editor needs a transformation before
+     * it can be used by the framework.
+     * Multivalue elements like select elements produce data like:
+     *
+     * [
+     *   _label => 'label'
+     *   _value => 'value'
+     * ]
+     *
+     * This method transform this into:
+     *
+     * [
+     *   'value' => 'label'
+     * ]
+     *
+     * @param array $input
+     * @return array
+     */
+    protected function convertJsonArrayToAssociativeArray(array $input): array
+    {
+        $output = [];
+        foreach ($input as $key => $value) {
+            if (is_integer($key) && is_array($value) && isset($value['_label']) && isset($value['_value'])) {
+                $key = $value['_value'];
+                $value = $value['_label'];
+            }
+            if (is_array($value)) {
+                $output[$key] = $this->convertJsonArrayToAssociativeArray($value);
+            } else {
+                $output[$key] = $value;
+            }
+        }
+        return $output;
+    }
+
+    /**
+     * Render the "text/x-formeditor-template" templates.
+     *
+     * @param array $formEditorTemplates
+     * @param array $formEditorDefinitions
+     * @return array
+     */
+    protected function renderFormEditorTemplates(array $formEditorTemplates, array $formEditorDefinitions): array
+    {
+        if (
+            !isset($formEditorTemplates['templateRootPaths'])
+            || !is_array($formEditorTemplates['templateRootPaths'])
+        ) {
+            throw new RenderingException(
+                'The option templateRootPaths must be set.',
+                1480294720
+            );
+        }
+        if (
+            !isset($formEditorTemplates['layoutRootPaths'])
+            || !is_array($formEditorTemplates['layoutRootPaths'])
+        ) {
+            throw new RenderingException(
+                'The option layoutRootPaths must be set.',
+                1480294721
+            );
+        }
+        if (
+            !isset($formEditorTemplates['partialRootPaths'])
+            || !is_array($formEditorTemplates['partialRootPaths'])
+        ) {
+            throw new RenderingException(
+                'The option partialRootPaths must be set.',
+                1480294722
+            );
+        }
+
+        $standaloneView = $this->objectManager->get(StandaloneView::class);
+        $standaloneView->setTemplateRootPaths($formEditorTemplates['templateRootPaths']);
+        $standaloneView->setLayoutRootPaths($formEditorTemplates['layoutRootPaths']);
+        $standaloneView->setPartialRootPaths($formEditorTemplates['partialRootPaths']);
+        $standaloneView->assignMultiple([
+            'insertRenderablesPanelConfiguration' => $this->getInsertRenderablesPanelConfiguration($formEditorDefinitions['formElements'])
+        ]);
+
+        unset($formEditorTemplates['templateRootPaths']);
+        unset($formEditorTemplates['layoutRootPaths']);
+        unset($formEditorTemplates['partialRootPaths']);
+
+        $renderedFormEditorTemplates = [];
+        foreach ($formEditorTemplates as $formEditorTemplateName => $formEditorTemplateTemplate) {
+            $renderedFormEditorTemplates[$formEditorTemplateName] = $standaloneView->render($formEditorTemplateTemplate);
+        }
+
+        return $renderedFormEditorTemplates;
+    }
+
+    /**
+     * Returns the current BE user.
+     *
+     * @return BackendUserAuthentication
+     */
+    protected function getBackendUser(): BackendUserAuthentication
+    {
+        return $GLOBALS['BE_USER'];
+    }
+
+    /**
+     * Returns the language service
+     *
+     * @return LanguageService
+     */
+    protected function getLanguageService(): LanguageService
+    {
+        return $GLOBALS['LANG'];
+    }
+}
diff --git a/typo3/sysext/form/Classes/Controller/FormFrontendController.php b/typo3/sysext/form/Classes/Controller/FormFrontendController.php
new file mode 100644
index 0000000000000000000000000000000000000000..41585604ce379999d65597265bb9e65d97fbca29
--- /dev/null
+++ b/typo3/sysext/form/Classes/Controller/FormFrontendController.php
@@ -0,0 +1,138 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Controller;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\ArrayUtility;
+use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
+use TYPO3\CMS\Form\Domain\Configuration\ConfigurationService;
+use TYPO3\CMS\Form\Mvc\Configuration\TypoScriptService;
+
+/**
+ * The frontend controller
+ *
+ * Scope: frontend
+ */
+class FormFrontendController extends ActionController
+{
+
+    /**
+     * @var \TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface
+     */
+    protected $formPersistenceManager;
+
+    /**
+     * @param \TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface $formPersistenceManager
+     * @return void
+     * @internal
+     */
+    public function injectFormPersistenceManager(\TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface $formPersistenceManager)
+    {
+        $this->formPersistenceManager = $formPersistenceManager;
+    }
+
+    /**
+     * Take the form which should be rendered from the plugin settings
+     * and overlay the formDefinition with additional data from
+     * flexform and typoscript settings.
+     * This method is used directly to display the first page from the
+     * formDefinition because its cached.
+     *
+     * @return void
+     * @internal
+     */
+    public function renderAction()
+    {
+        $formDefinition = [];
+        if (!empty($this->settings['persistenceIdentifier'])) {
+            $formDefinition = $this->formPersistenceManager->load($this->settings['persistenceIdentifier']);
+            $formDefinition['persistenceIdentifier'] = $this->settings['persistenceIdentifier'];
+            $formDefinition = $this->overrideByFlexFormSettings($formDefinition);
+            $formDefinition = $this->overrideByTypoScriptSettings($formDefinition);
+        }
+        $this->view->assign('formConfiguration', $formDefinition);
+    }
+
+    /**
+     * This method is used to display all pages / finishers except the
+     * first page because its non cached.
+     *
+     * @return void
+     * @internal
+     */
+    public function performAction()
+    {
+        $this->forward('render');
+    }
+
+    /**
+     * Override the formDefinition with additional data from the Flexform
+     * settings. For now, only finisher settings are overridable.
+     *
+     * @param array $formDefinition
+     * @return array
+     */
+    protected function overrideByFlexFormSettings(array $formDefinition): array
+    {
+        if (isset($formDefinition['finishers'])) {
+            foreach ($formDefinition['finishers'] as &$finisherValue) {
+                $finisherIdentifier = $finisherValue['identifier'];
+                if ($this->settings['overrideFinishers'] && isset($this->settings['finishers'][$finisherIdentifier])) {
+                    $prototypeName = isset($formDefinition['prototypeName']) ? $formDefinition['prototypeName'] : 'standard';
+                    $configurationService = $this->objectManager->get(ConfigurationService::class);
+                    $prototypeConfiguration = $configurationService->getPrototypeConfiguration($prototypeName);
+
+                    foreach ($finisherValue['options'] as $optionKey => $optionValue) {
+                        // If a previous overriden finisher property is excluded at some time
+                        // it is still present in the flexform database row.
+                        // To avoid a override from the time the property is excluded, this check is needed
+                        if (!isset($prototypeConfiguration['finishersDefinition'][$finisherIdentifier]['FormEngine']['elements'][$optionKey])) {
+                            continue;
+                        }
+                        if (isset($this->settings['finishers'][$finisherIdentifier][$optionKey])) {
+                            $finisherValue['options'][$optionKey] = $this->settings['finishers'][$finisherIdentifier][$optionKey];
+                        }
+                    }
+                }
+            }
+        }
+        return $formDefinition;
+    }
+
+    /**
+     * Every formDefinition setting are overridable by typoscript.
+     * If the typoscript configuration path
+     * plugin.tx_form.settings.formDefinitionOverrides.<identifier>
+     * exists, this settings are merged into the formDefinition.
+     *
+     * @param array $formDefinition
+     * @return array
+     */
+    protected function overrideByTypoScriptSettings(array $formDefinition): array
+    {
+        if (
+            isset($this->settings['formDefinitionOverrides'][$formDefinition['identifier']])
+            && !empty($this->settings['formDefinitionOverrides'][$formDefinition['identifier']])
+        ) {
+            ArrayUtility::mergeRecursiveWithOverrule(
+                $formDefinition,
+                $this->settings['formDefinitionOverrides'][$formDefinition['identifier']]
+            );
+            $formDefinition = $this->objectManager->get(TypoScriptService::class)
+                ->resolvePossibleTypoScriptConfiguration($formDefinition);
+        }
+        return $formDefinition;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Controller/FormManagerController.php b/typo3/sysext/form/Classes/Controller/FormManagerController.php
new file mode 100644
index 0000000000000000000000000000000000000000..a45ada81cc5681f54f2965a8f8b975ea6f42fde2
--- /dev/null
+++ b/typo3/sysext/form/Classes/Controller/FormManagerController.php
@@ -0,0 +1,463 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Controller;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Symfony\Component\Yaml\Yaml;
+use TYPO3\CMS\Backend\Template\Components\ButtonBar;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Backend\View\BackendTemplateView;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Imaging\Icon;
+use TYPO3\CMS\Core\Imaging\IconFactory;
+use TYPO3\CMS\Core\Messaging\AbstractMessage;
+use TYPO3\CMS\Core\Page\PageRenderer;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Mvc\View\JsonView;
+use TYPO3\CMS\Form\Exception as FormException;
+use TYPO3\CMS\Form\Service\TranslationService;
+use TYPO3\CMS\Form\Utility\ArrayUtility;
+use TYPO3\CMS\Lang\LanguageService;
+
+/**
+ * The form manager controller
+ *
+ * Scope: backend
+ */
+class FormManagerController extends AbstractBackendController
+{
+
+    /**
+     * Default View Container
+     *
+     * @var BackendTemplateView
+     */
+    protected $defaultViewObjectName = BackendTemplateView::class;
+
+    /**
+     * Initialize the references action.
+     * This action use the Fluid JsonView::class as view.
+     *
+     * @return void
+     * @internal
+     */
+    public function initializeReferencesAction()
+    {
+        $this->defaultViewObjectName = JsonView::class;
+    }
+
+    /**
+     * Displays the Form Manager
+     *
+     * @return void
+     * @internal
+     */
+    public function indexAction()
+    {
+        $this->registerDocheaderButtons();
+        $this->view->getModuleTemplate()->setModuleName($this->request->getPluginName() . '_' . $this->request->getControllerName());
+        $this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue());
+
+        $this->view->assign('forms', $this->getAvailableFormDefinitions());
+        $this->view->assign('stylesheets', $this->resolveResourcePaths($this->formSettings['formManager']['stylesheets']));
+        $this->view->assign('dynamicRequireJsModules', $this->formSettings['formManager']['dynamicRequireJsModules']);
+        $this->view->assign('formManagerAppInitialData', $this->getFormManagerAppInitialData());
+        if (!empty($this->formSettings['formManager']['javaScriptTranslationFile'])) {
+            $this->getPageRenderer()->addInlineLanguageLabelFile($this->formSettings['formManager']['javaScriptTranslationFile']);
+        }
+    }
+
+    /**
+     * Creates a new Form and redirects to the Form Editor
+     *
+     * @param string $formName
+     * @param string $templatePath
+     * @param string $prototypeName
+     * @param string $savePath
+     * @return string
+     * @throws FormException
+     * @internal
+     */
+    public function createAction(string $formName, string $templatePath, string $prototypeName, string $savePath): string
+    {
+        if (!$this->isValidTemplatePath($prototypeName, $templatePath)) {
+            throw new FormException(sprintf('The template path "%s" is not allowed', $templatePath), 1329233410);
+        }
+        if (empty($formName)) {
+            throw new FormException(sprintf('No form name', $templatePath), 1472312204);
+        }
+
+        $templatePath = GeneralUtility::getFileAbsFileName($templatePath);
+        $form = Yaml::parse(file_get_contents($templatePath));
+        $form['label'] = $formName;
+        $form['identifier'] = $this->formPersistenceManager->getUniqueIdentifier($this->convertFormNameToIdentifier($formName));
+        $form['prototypeName'] = $prototypeName;
+
+        $formPersistenceIdentifier = $this->formPersistenceManager->getUniquePersistenceIdentifier($form['identifier'], $savePath);
+        $this->formPersistenceManager->save($formPersistenceIdentifier, $form);
+
+        return $this->controllerContext->getUriBuilder()->uriFor('index', ['formPersistenceIdentifier' => $formPersistenceIdentifier], 'FormEditor');
+    }
+
+    /**
+     * Duplicates a given formDefinition and redirects to the Form Editor
+     *
+     * @param string $formName
+     * @param string $formPersistenceIdentifier persistence identifier of the form to duplicate
+     * @param string $savePath
+     * @return string
+     * @internal
+     */
+    public function duplicateAction(string $formName, string $formPersistenceIdentifier, string $savePath): string
+    {
+        $formToDuplicate = $this->formPersistenceManager->load($formPersistenceIdentifier);
+        $formToDuplicate['label'] = $formName;
+        $formToDuplicate['identifier'] = $this->formPersistenceManager->getUniqueIdentifier($this->convertFormNameToIdentifier($formName));
+
+        $formPersistenceIdentifier = $this->formPersistenceManager->getUniquePersistenceIdentifier($formToDuplicate['identifier'], $savePath);
+        $this->formPersistenceManager->save($formPersistenceIdentifier, $formToDuplicate);
+
+        return $this->controllerContext->getUriBuilder()->uriFor('index', ['formPersistenceIdentifier' => $formPersistenceIdentifier], 'FormEditor');
+    }
+
+    /**
+     * Show references to this persistence identifier
+     *
+     * @param string $formPersistenceIdentifier persistence identifier of the form to duplicate
+     * @return void
+     * @internal
+     */
+    public function referencesAction(string $formPersistenceIdentifier)
+    {
+        $this->view->assign('references', $this->getProcessedReferencesRows($formPersistenceIdentifier));
+        $this->view->assign('formPersistenceIdentifier', $formPersistenceIdentifier);
+        // referencesAction uses the extbase JsonView::class.
+        // That's why we have to set the view variables in this way.
+        $this->view->setVariablesToRender([
+            'references',
+            'formPersistenceIdentifier'
+        ]);
+    }
+
+    /**
+     * Delete a formDefinition identified by the $formPersistenceIdentifier.
+     * Only formDefinitions within storage folders are deletable.
+     *
+     * @param string $formPersistenceIdentifier persistence identifier to delete
+     * @return void
+     * @internal
+     */
+    public function deleteAction(string $formPersistenceIdentifier)
+    {
+        if (
+            empty($this->getReferences($formPersistenceIdentifier))
+            && strpos($formPersistenceIdentifier, 'EXT:') === false
+        ) {
+            $this->formPersistenceManager->delete($formPersistenceIdentifier);
+        } else {
+            $this->addFlashMessage(
+                TranslationService::getInstance()->translate(
+                    $this->formSettings['formManager']['controller']['deleteAction']['errorMessage'],
+                    [$formPersistenceIdentifier],
+                    $this->formSettings['formManager']['translationFile'],
+                    null,
+                    $this->formSettings['formManager']['controller']['deleteAction']['errorMessage']
+                ),
+                TranslationService::getInstance()->translate(
+                    $this->formSettings['formManager']['controller']['deleteAction']['errorTitle'],
+                    null,
+                    $this->formSettings['formManager']['translationFile'],
+                    null,
+                    $this->formSettings['formManager']['controller']['deleteAction']['errorTitle']
+                ),
+                AbstractMessage::ERROR,
+                true
+            );
+        }
+        $this->redirect('index');
+    }
+
+    /**
+     * Return a list of all accessible file mountpoints.
+     *
+     * Only registered mountpoints from
+     * TYPO3.CMS.Form.persistenceManager.allowedFileMounts
+     * are listet. This is list will be reduced by the configured
+     * mountpoints for the current backend user.
+     *
+     * @return array
+     */
+    protected function getAccessibleFormStorageFolders(): array
+    {
+        $preparedAccessibleFormStorageFolders = [];
+        foreach ($this->formPersistenceManager->getAccessibleFormStorageFolders() as $identifier => $folder) {
+            $preparedAccessibleFormStorageFolders[] = [
+                'label' => $folder->getName(),
+                'value' => $identifier
+            ];
+        }
+        return $preparedAccessibleFormStorageFolders;
+    }
+
+    /**
+     * Returns the json encoded data which is used by the form editor
+     * JavaScript app.
+     *
+     * @return string
+     */
+    protected function getFormManagerAppInitialData(): string
+    {
+        $formManagerAppInitialData = [
+            'selectablePrototypesConfiguration' => $this->formSettings['formManager']['selectablePrototypesConfiguration'],
+            'accessibleFormStorageFolders' => $this->getAccessibleFormStorageFolders(),
+            'endpoints' => [
+                'create' => $this->controllerContext->getUriBuilder()->uriFor('create'),
+                'duplicate' => $this->controllerContext->getUriBuilder()->uriFor('duplicate'),
+                'delete' => $this->controllerContext->getUriBuilder()->uriFor('delete'),
+                'references' => $this->controllerContext->getUriBuilder()->uriFor('references')
+            ],
+        ];
+
+        $formManagerAppInitialData = ArrayUtility::reIndexNumericArrayKeysRecursive($formManagerAppInitialData);
+        $formManagerAppInitialData = TranslationService::getInstance()->translateValuesRecursive(
+            $formManagerAppInitialData,
+            $this->formSettings['formManager']['translationFile']
+        );
+        return json_encode($formManagerAppInitialData);
+    }
+
+    /**
+     * List all formDefinitions which can be loaded through t form persistence
+     * manager. Enrich this data by a reference counter.
+     * @return array
+     */
+    protected function getAvailableFormDefinitions(): array
+    {
+        $availableFormDefinitions = [];
+        foreach ($this->formPersistenceManager->listForms() as $formDefinition) {
+            $referenceCount = count($this->getReferences($formDefinition['persistenceIdentifier']));
+            $formDefinition['referenceCount'] = $referenceCount;
+            $availableFormDefinitions[] = $formDefinition;
+        }
+        return $availableFormDefinitions;
+    }
+
+    /**
+     * Returns an array with informations about the references for a
+     * formDefinition identified by $persistenceIdentifier.
+     *
+     * @param string $persistenceIdentifier
+     * @return array
+     * @throws \InvalidArgumentException
+     */
+    protected function getProcessedReferencesRows(string $persistenceIdentifier): array
+    {
+        if (empty($persistenceIdentifier)) {
+            throw new \InvalidArgumentException('$persistenceIdentifier must not be empty.', 1477071939);
+        }
+
+        $references = [];
+        $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
+
+        $referenceRows = $this->getReferences($persistenceIdentifier);
+        foreach ($referenceRows as &$referenceRow) {
+            $record = $this->getBackendUtility()::getRecord($referenceRow['tablename'], $referenceRow['recuid']);
+            if (!$record) {
+                continue;
+            }
+            $pageRecord = $this->getBackendUtility()::getRecord('pages', $record['pid']);
+            $urlParameters = [
+                'edit' => [
+                    $referenceRow['tablename'] => [
+                        $referenceRow['recuid'] => 'edit'
+                    ]
+                ],
+                'returnUrl' => $this->getBackendUtility()::getModuleUrl('web_FormFormbuilder')
+            ];
+
+            $references[] = [
+                'recordPageTitle' => is_array($pageRecord) ? $this->getBackendUtility()::getRecordTitle('pages', $pageRecord) : '',
+                'recordTitle' => $this->getBackendUtility()::getRecordTitle($referenceRow['tablename'], $record, true),
+                'recordIcon' => $iconFactory->getIconForRecord($referenceRow['tablename'], $record, Icon::SIZE_SMALL)->render(),
+                'recordUid' => $referenceRow['recuid'],
+                'recordEditUrl' => $this->getBackendUtility()::getModuleUrl('record_edit', $urlParameters),
+            ];
+        }
+        return $references;
+    }
+
+    /**
+     * Returns an array with all sys_refindex database rows which be
+     * connected to a formDefinition identified by $persistenceIdentifier
+     *
+     * @param string $persistenceIdentifier
+     * @return array
+     * @throws \InvalidArgumentException
+     */
+    protected function getReferences(string $persistenceIdentifier): array
+    {
+        if (empty($persistenceIdentifier)) {
+            throw new \InvalidArgumentException('$persistenceIdentifier must not be empty.', 1472238493);
+        }
+
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_refindex');
+        $referenceRows = $queryBuilder
+            ->select('*')
+            ->from('sys_refindex')
+            ->where(
+                $queryBuilder->expr()->eq('deleted', 0),
+                $queryBuilder->expr()->eq('softref_key', $queryBuilder->createNamedParameter('formPersistenceIdentifier', \PDO::PARAM_STR)),
+                $queryBuilder->expr()->eq('ref_string', $queryBuilder->createNamedParameter($persistenceIdentifier, \PDO::PARAM_STR)),
+                $queryBuilder->expr()->eq('tablename', $queryBuilder->createNamedParameter('tt_content', \PDO::PARAM_STR))
+            )
+            ->execute()
+            ->fetchAll();
+        return $referenceRows;
+    }
+
+    /**
+     * Check if a given $templatePath for a given $prototypeName is valid
+     * and accessible.
+     *
+     * Valid template paths has to be configured within
+     * TYPO3.CMS.Form.formManager.selectablePrototypesConfiguration.[('identifier':  $prototypeName)].newFormTemplates.[('templatePath': $templatePath)]
+     *
+     * @param string $prototypeName
+     * @param string $templatePath
+     * @return bool
+     */
+    protected function isValidTemplatePath(string $prototypeName, string $templatePath): bool
+    {
+        $isValid = false;
+        foreach ($this->formSettings['formManager']['selectablePrototypesConfiguration'] as $prototypesConfiguration) {
+            if ($prototypesConfiguration['identifier'] !== $prototypeName) {
+                continue;
+            }
+            foreach ($prototypesConfiguration['newFormTemplates'] as $templatesConfiguration) {
+                if ($templatesConfiguration['templatePath'] !== $templatePath) {
+                    continue;
+                }
+                $isValid = true;
+                break;
+            }
+        }
+
+        $templatePath = GeneralUtility::getFileAbsFileName($templatePath);
+        if (!is_file($templatePath)) {
+            $isValid = false;
+        }
+
+        return $isValid;
+    }
+
+    /**
+     * Registers the Icons into the docheader
+     *
+     * @throws \InvalidArgumentException
+     */
+    protected function registerDocheaderButtons()
+    {
+        /** @var ButtonBar $buttonBar */
+        $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
+        $currentRequest = $this->request;
+        $moduleName = $currentRequest->getPluginName();
+        $getVars = $this->request->getArguments();
+
+        $mayMakeShortcut = $this->getBackendUser()->mayMakeShortcut();
+        if ($mayMakeShortcut) {
+            $extensionName = $currentRequest->getControllerExtensionName();
+            if (count($getVars) === 0) {
+                $modulePrefix = strtolower('tx_' . $extensionName . '_' . $moduleName);
+                $getVars = ['id', 'M', $modulePrefix];
+            }
+
+            $shortcutButton = $buttonBar->makeShortcutButton()
+                ->setModuleName($moduleName)
+                ->setDisplayName($this->getLanguageService()->sL('LLL:EXT:form/Resources/Private/Language/Database.xlf:module.shortcut_name'))
+                ->setGetVariables($getVars);
+            $buttonBar->addButton($shortcutButton);
+        }
+
+        if (isset($getVars['action']) && $getVars['action'] !== 'index') {
+            $backButton = $buttonBar->makeLinkButton()
+                ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/locallang_common.xlf:back'))
+                ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-up', Icon::SIZE_SMALL))
+                ->setHref($this->getBackendUtility()::getModuleUrl($moduleName));
+            $buttonBar->addButton($backButton);
+        } else {
+            $addFormButton = $buttonBar->makeLinkButton()
+                ->setDataAttributes(['identifier' => 'newForm'])
+                ->setHref('#')
+                ->setTitle($this->getLanguageService()->sL('LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.create_new_form'))
+                ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-document-new', Icon::SIZE_SMALL));
+            $buttonBar->addButton($addFormButton, ButtonBar::BUTTON_POSITION_LEFT);
+        }
+    }
+
+    /**
+     * Returns a form identifier which is the lower cased form name.
+     *
+     * @param string $formName
+     * @return string
+     */
+    protected function convertFormNameToIdentifier(string $formName): string
+    {
+        $formIdentifier = preg_replace('/[^a-zA-Z0-9-_]/', '', $formName);
+        $formIdentifier = lcfirst($formIdentifier);
+        return $formIdentifier;
+    }
+
+    /**
+     * Returns the BackendUtility
+     * This wrapper is needed for unit tests.
+     *
+     * @return string
+     */
+    protected function getBackendUtility(): string
+    {
+        return BackendUtility::class;
+    }
+
+    /**
+     * Returns the current BE user.
+     *
+     * @return BackendUserAuthentication
+     */
+    protected function getBackendUser(): BackendUserAuthentication
+    {
+        return $GLOBALS['BE_USER'];
+    }
+
+    /**
+     * Returns the Language Service
+     *
+     * @return LanguageService
+     */
+    protected function getLanguageService(): LanguageService
+    {
+        return $GLOBALS['LANG'];
+    }
+
+    /**
+     * Returns the page renderer
+     *
+     * @return PageRenderer
+     */
+    protected function getPageRenderer(): PageRenderer
+    {
+        return GeneralUtility::makeInstance(PageRenderer::class);
+    }
+}
diff --git a/typo3/sysext/form/Classes/Controller/FrontendController.php b/typo3/sysext/form/Classes/Controller/FrontendController.php
deleted file mode 100644
index 43fd2035ea930d435b31fc56fa715d7e7b6e6655..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Controller/FrontendController.php
+++ /dev/null
@@ -1,342 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Controller;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
-use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
-use TYPO3\CMS\Form\Domain\Builder\FormBuilder;
-use TYPO3\CMS\Form\Domain\Builder\ValidationBuilder;
-use TYPO3\CMS\Form\Domain\Model\Configuration;
-use TYPO3\CMS\Form\Domain\Model\ValidationElement;
-use TYPO3\CMS\Form\Mvc\Controller\ControllerContext;
-use TYPO3\CMS\Form\Utility\FormUtility;
-
-/**
- * The form wizard controller
- */
-class FrontendController extends ActionController
-{
-    /**
-     * @var FormBuilder
-     */
-    protected $formBuilder;
-
-    /**
-     * @var ValidationBuilder
-     */
-    protected $validationBuilder;
-
-    /**
-     * @var \TYPO3\CMS\Form\Utility\SessionUtility
-     */
-    protected $sessionUtility;
-
-    /**
-     * @var FormUtility
-     */
-    protected $formUtility;
-
-    /**
-     * The TypoScript array
-     *
-     * @var array
-     */
-    protected $typoscript = [];
-
-    /**
-     * TRUE if the validation of the form should be skipped
-     *
-     * @var bool
-     */
-    protected $skipValidation = false;
-
-    /**
-     * @var ControllerContext
-     */
-    protected $controllerContext;
-
-    /**
-     * @var Configuration
-     */
-    protected $configuration;
-
-    /**
-     * @param \TYPO3\CMS\Form\Utility\SessionUtility $sessionUtility
-     * @return void
-     */
-    public function injectSessionUtility(\TYPO3\CMS\Form\Utility\SessionUtility $sessionUtility)
-    {
-        $this->sessionUtility = $sessionUtility;
-    }
-
-    /**
-     * initialize action
-     *
-     * @return void
-     */
-    protected function initializeAction()
-    {
-        $this->configuration = Configuration::create()->setTypoScript($this->settings['typoscript']);
-        $this->formUtility = FormUtility::create($this->configuration);
-        $this->validationBuilder = ValidationBuilder::create($this->configuration);
-        $this->validationBuilder->setFormUtility($this->formUtility);
-        $this->formBuilder = FormBuilder::create($this->configuration);
-        $this->formBuilder->setValidationBuilder($this->validationBuilder);
-        $this->formBuilder->setFormUtility($this->formUtility);
-        $this->typoscript = $this->settings['typoscript'];
-
-            // uploaded file storage
-        $this->sessionUtility->initSession($this->configuration->getPrefix());
-            // move the incoming "formPrefix" data to the $model argument
-            // now we can validate the $model argument
-        if ($this->request->hasArgument($this->configuration->getPrefix())) {
-            $this->skipValidation = false;
-            $argument = $this->request->getArgument($this->configuration->getPrefix());
-            $this->request->setArgument('model', $argument);
-        } else {
-            // If there are more forms at a page we have to skip
-            // the validation of not submitted forms
-            $this->skipValidation = true;
-            $this->request->setArgument('model', []);
-        }
-    }
-
-    /**
-     * initialize show action
-     *
-     * @return void
-     */
-    protected function initializeShowAction()
-    {
-        $validationResults = $this->request->getOriginalRequestMappingResults()->forProperty('model');
-        $this->validationBuilder->buildRules();
-        if ($validationResults->hasErrors()) {
-            $this->formBuilder->setValidationErrors($validationResults);
-        }
-    }
-
-    /**
-     * initialize the confirmation action
-     *
-     * @return void
-     */
-    protected function initializeConfirmationAction()
-    {
-        $this->prepareValidations();
-    }
-
-    /**
-     * initialize the process action
-     *
-     * @return void
-     */
-    protected function initializeProcessAction()
-    {
-        $this->prepareValidations();
-    }
-
-    /**
-     * Builds the controller context by extending
-     * the Extbase context with custom additions.
-     *
-     * @return ControllerContext
-     */
-    protected function buildControllerContext()
-    {
-        $controllerContext = ControllerContext::extend(parent::buildControllerContext())
-            ->setConfiguration($this->configuration);
-        $this->formBuilder->setControllerContext($controllerContext);
-        return $controllerContext;
-    }
-
-    /**
-     * Handles show action, presenting the actual form.
-     *
-     * @param \TYPO3\CMS\Form\Domain\Model\ValidationElement $incomingData
-     * @ignorevalidation $incomingData
-     * @return void
-     */
-    public function showAction(ValidationElement $incomingData = null)
-    {
-        if ($incomingData !== null) {
-            $this->controllerContext->setValidationElement($incomingData);
-        }
-        $form = $this->formBuilder->buildModel();
-        $this->view->assign('model', $form);
-    }
-
-    /**
-     * Handles confirmation action, presenting the user submitted
-     * data again for final confirmation.
-     *
-     * @param \TYPO3\CMS\Form\Domain\Model\ValidationElement $model
-     * @return void
-     */
-    public function confirmationAction(ValidationElement $model)
-    {
-        $this->skipForeignFormProcessing();
-
-        if (count($model->getIncomingFields()) === 0) {
-            $this->sessionUtility->destroySession();
-            $this->forward('show');
-        }
-        $this->controllerContext->setValidationElement($model);
-        $form = $this->formBuilder->buildModel();
-        // store uploaded files
-        $this->sessionUtility->storeSession();
-        $this->view->assign('model', $form);
-
-        $message = $this->formUtility->renderItem(
-            $this->typoscript['confirmation.']['message.'],
-            $this->typoscript['confirmation.']['message'],
-            LocalizationUtility::translate('tx_form_view_confirmation.message', 'form')
-        );
-        $this->view->assign('message', $message);
-    }
-
-    /**
-     * action dispatchConfirmationButtonClick
-     *
-     * @param \TYPO3\CMS\Form\Domain\Model\ValidationElement $model
-     * @return void
-     */
-    public function dispatchConfirmationButtonClickAction(ValidationElement $model)
-    {
-        $this->skipForeignFormProcessing();
-
-        if ($this->request->hasArgument('confirmation-true')) {
-            $this->forward('process', null, null, [$this->configuration->getPrefix() => $this->request->getArgument('model')]);
-        } else {
-            $this->sessionUtility->destroySession();
-            $this->forward('show', null, null, ['incomingData' => $this->request->getArgument('model')]);
-        }
-    }
-
-    /**
-     * Handles process action, actually processing the user
-     * submitted data and forwarding it to post-processors
-     * (e.g. sending out mail messages).
-     *
-     * @param \TYPO3\CMS\Form\Domain\Model\ValidationElement $model
-     * @return void
-     */
-    public function processAction(ValidationElement $model)
-    {
-        $this->skipForeignFormProcessing();
-
-        $this->controllerContext->setValidationElement($model);
-        $form = $this->formBuilder->buildModel();
-        $postProcessorTypoScript = [];
-        if (isset($this->typoscript['postProcessor.'])) {
-            $postProcessorTypoScript = $this->typoscript['postProcessor.'];
-        }
-
-        /** @var $postProcessor \TYPO3\CMS\Form\PostProcess\PostProcessor */
-        $postProcessor = $this->objectManager->get(
-            \TYPO3\CMS\Form\PostProcess\PostProcessor::class,
-            $form, $postProcessorTypoScript
-        );
-        $postProcessor->setControllerContext($this->controllerContext);
-
-        // @todo What is happening here?
-        $content = $postProcessor->process();
-        $this->sessionUtility->destroySession();
-        $this->forward('afterProcess', null, null, ['postProcessorContent' => $content]);
-    }
-
-    /**
-     * action after process
-     *
-     * @param string $postProcessorContent
-     * @return void
-     */
-    public function afterProcessAction($postProcessorContent)
-    {
-        $this->view->assign('postProcessorContent', $postProcessorContent);
-    }
-
-    /**
-     * Skip the processing of foreign forms.
-     * If there is more than one form on a page
-     * we have to be sure that only the submitted form will be
-     * processed. On data submission, the extbase action "confirmation" or
-     * "process" is called. The detection which form is submitted
-     * is done by the form prefix. All forms which do not have any
-     * submitted data are skipped and forwarded to the show action.
-     *
-     * @return void
-     */
-    protected function skipForeignFormProcessing()
-    {
-        if (
-            !$this->request->hasArgument($this->configuration->getPrefix())
-            && !$this->sessionUtility->getSessionData()
-        ) {
-            $this->forward('show');
-        }
-    }
-
-    /**
-     * If the current form should be validated
-     * then set the dynamic validation
-     *
-     * @return void
-     */
-    protected function prepareValidations()
-    {
-        if ($this->skipValidation || !$this->arguments->hasArgument('model')) {
-            return;
-        }
-
-        $this->validationBuilder->buildRules($this->request->getArgument('model'));
-        $this->setDynamicValidation($this->validationBuilder->getRules());
-        $this->skipValidation = false;
-    }
-
-    /**
-     * Sets the dynamic validation rules.
-     *
-     * @param array $toValidate
-     * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException
-     * @throws \TYPO3\CMS\Extbase\Validation\Exception\NoSuchValidatorException
-     */
-    protected function setDynamicValidation(array $toValidate = [])
-    {
-        // build custom validation chain
-        /** @var \TYPO3\CMS\Extbase\Validation\ValidatorResolver $validatorResolver */
-        $validatorResolver = $this->objectManager->get(\TYPO3\CMS\Extbase\Validation\ValidatorResolver::class);
-
-        /** @var \TYPO3\CMS\Form\Domain\Validator\ValidationElementValidator $modelValidator */
-        $modelValidator = $validatorResolver->createValidator(\TYPO3\CMS\Form\Domain\Validator\ValidationElementValidator::class);
-        foreach ($toValidate as $propertyName => $validations) {
-            foreach ($validations as $validation) {
-                if (empty($validation['validator'])) {
-                    throw new \TYPO3\CMS\Extbase\Validation\Exception\NoSuchValidatorException('Invalid validate configuration for ' . $propertyName . ': Could not resolve class name for validator "' . $validation['validatorName'] . '".', 1441893777);
-                }
-                $modelValidator->addPropertyValidator($propertyName, $validation['validator']);
-            }
-        }
-
-        if ($modelValidator->countPropertyValidators()) {
-            /** @var \TYPO3\CMS\Extbase\Validation\Validator\ConjunctionValidator $baseConjunctionValidator */
-            $baseConjunctionValidator = $this->arguments->getArgument('model')->getValidator();
-            if ($baseConjunctionValidator === null) {
-                $baseConjunctionValidator = $validatorResolver->createValidator(\TYPO3\CMS\Extbase\Validation\Validator\ConjunctionValidator::class);
-                $this->arguments->getArgument('model')->setValidator($baseConjunctionValidator);
-            }
-            $baseConjunctionValidator->addValidator($modelValidator);
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Controller/WizardController.php b/typo3/sysext/form/Classes/Controller/WizardController.php
deleted file mode 100644
index e7185dc80f9a0a8d9c23c029bc01e5e18510aea1..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Controller/WizardController.php
+++ /dev/null
@@ -1,92 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Controller;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Form\Domain\Repository\ContentRepository;
-
-/**
- * The form wizard controller
- */
-class WizardController
-{
-    /**
-     * The constructor to load the LL file
-     */
-    public function __construct()
-    {
-        $this->getLanguageService()->includeLLFile('EXT:form/Resources/Private/Language/locallang_wizard.xlf');
-    }
-
-    /**
-     * The save action called via AJAX
-     *
-     * The action which should be taken when the form in the wizard is saved
-     *
-     * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
-     * @return ResponseInterface returns a 500 error or a valid JSON response
-     */
-    public function saveAction(ServerRequestInterface $request, ResponseInterface $response)
-    {
-        $repository = $this->getRepository();
-        $typoscript = '';
-        $jsonArray = [];
-
-        // Check if the referenced record is available
-        if ($repository->hasRecord()) {
-            // Save the data
-            $typoscript = $repository->save();
-        }
-
-        if (!$typoscript) {
-            $response = $response->withStatus(500);
-            $message = $this->getLanguageService()->getLL('action_save_message_failed', false);
-        } else {
-            $message = $this->getLanguageService()->getLL('action_save_message_saved', false);
-            $jsonArray['fakeTs'] = $typoscript;
-        }
-
-        $jsonArray['message'] = $message;
-        $response->getBody()->write(json_encode($jsonArray));
-        return $response
-                ->withHeader('Expires', 'Mon, 26 Jul 1997 05:00:00 GMT')
-                ->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT')
-                ->withHeader('Cache-Control', 'no-cache, must-revalidate')
-                ->withHeader('Pragma', 'no-cache');
-    }
-
-    /**
-     * Gets the repository object.
-     *
-     * @return ContentRepository
-     */
-    protected function getRepository()
-    {
-        return GeneralUtility::makeInstance(ContentRepository::class);
-    }
-
-    /**
-     * Returns an instance of LanguageService
-     *
-     * @return \TYPO3\CMS\Lang\LanguageService
-     */
-    protected function getLanguageService()
-    {
-        return $GLOBALS['LANG'];
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Builder/ElementBuilder.php b/typo3/sysext/form/Classes/Domain/Builder/ElementBuilder.php
deleted file mode 100644
index c2b0023ff4fa06c34285bc0c22ba4b04fc5bb5fe..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Builder/ElementBuilder.php
+++ /dev/null
@@ -1,510 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Builder;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\MathUtility;
-use TYPO3\CMS\Form\Domain\Model\Element;
-
-/**
- * Builder for Element domain models.
- */
-class ElementBuilder
-{
-    /**
-     * @param FormBuilder $formBuilder
-     * @param Element $element
-     * @param array $userDefinedTypoScript
-     * @return ElementBuilder
-     */
-    public static function create(FormBuilder $formBuilder, Element $element, array $userDefinedTypoScript)
-    {
-        /** @var ElementBuilder $elementBuilder */
-        $elementBuilder = \TYPO3\CMS\Form\Utility\FormUtility::getObjectManager()->get(self::class);
-        $elementBuilder->setFormBuilder($formBuilder);
-        $elementBuilder->setElement($element);
-        $elementBuilder->setUserConfiguredElementTyposcript($userDefinedTypoScript);
-        return $elementBuilder;
-    }
-
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository
-     */
-    protected $typoScriptRepository;
-
-    /**
-     * @var \TYPO3\CMS\Extbase\Service\TypoScriptService
-     */
-    protected $typoScriptService;
-
-    /**
-     * @var array
-     */
-    protected $userConfiguredElementTyposcript = [];
-
-    /**
-     * @var array
-     */
-    protected $htmlAttributes = [];
-
-    /**
-     * @var array
-     */
-    protected $additionalArguments = [];
-
-    /**
-     * @var array
-     */
-    protected $wildcardPrefixes = [];
-
-    /**
-     * @var FormBuilder
-     */
-    protected $formBuilder;
-
-    /**
-     * @var Element
-     */
-    protected $element;
-
-    /**
-     * @param \TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository $typoScriptRepository
-     * @return void
-     */
-    public function injectTypoScriptRepository(\TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository $typoScriptRepository)
-    {
-        $this->typoScriptRepository = $typoScriptRepository;
-    }
-
-    /**
-     * @param \TYPO3\CMS\Extbase\Service\TypoScriptService $typoScriptService
-     * @return void
-     */
-    public function injectTypoScriptService(\TYPO3\CMS\Extbase\Service\TypoScriptService $typoScriptService)
-    {
-        $this->typoScriptService = $typoScriptService;
-    }
-
-    /**
-     * @param FormBuilder $formBuilder
-     */
-    public function setFormBuilder(FormBuilder $formBuilder)
-    {
-        $this->formBuilder = $formBuilder;
-    }
-
-    /**
-     * @param Element $element
-     */
-    public function setElement(Element $element)
-    {
-        $this->element = $element;
-    }
-
-    /**
-     * Set the fluid partial path to the element
-     *
-     * @return void
-     */
-    public function setPartialPaths()
-    {
-        $this->setElementPartialPath();
-    }
-
-    /**
-     * Set the fluid partial path to the element
-     *
-     * @return void
-     */
-    protected function setElementPartialPath()
-    {
-        if (!isset($this->userConfiguredElementTyposcript['partialPath'])) {
-            $partialPath = $this->typoScriptRepository->getDefaultFluidTemplate($this->element->getElementType());
-        } else {
-            $partialPath = $this->userConfiguredElementTyposcript['partialPath'];
-            unset($this->userConfiguredElementTyposcript['partialPath']);
-        }
-        $this->element->setPartialPath($partialPath);
-    }
-
-    /**
-     * Set the fluid partial path to the element
-     *
-     * @return void
-     */
-    public function setVisibility()
-    {
-        $visibility = false;
-        if ($this->formBuilder->getControllerAction() === 'show') {
-            if (!isset($this->userConfiguredElementTyposcript['visibleInShowAction'])) {
-                $visibility = (bool)$this->typoScriptRepository->getModelConfigurationByScope($this->element->getElementType(), 'visibleInShowAction');
-            } else {
-                $visibility = (bool)$this->userConfiguredElementTyposcript['visibleInShowAction'];
-            }
-        } elseif ($this->formBuilder->getControllerAction() === 'confirmation') {
-            if (!isset($this->userConfiguredElementTyposcript['visibleInConfirmationAction'])) {
-                $visibility = (bool)$this->typoScriptRepository->getModelConfigurationByScope($this->element->getElementType(), 'visibleInConfirmationAction');
-            } else {
-                $visibility = (bool)$this->userConfiguredElementTyposcript['visibleInConfirmationAction'];
-            }
-        } elseif ($this->formBuilder->getControllerAction() === 'process') {
-            if (!isset($this->userConfiguredElementTyposcript['visibleInMail'])) {
-                $visibility = (bool)$this->typoScriptRepository->getModelConfigurationByScope($this->element->getElementType(), 'visibleInMail');
-            } else {
-                $visibility = (bool)$this->userConfiguredElementTyposcript['visibleInMail'];
-            }
-        }
-        $this->element->setShowElement($visibility);
-    }
-
-    /**
-     * Find all prefix-* attributes and return the
-     * found prefixs. Than delete them from the htmlAttributes array
-     *
-     * @return void
-     */
-    public function setHtmlAttributeWildcards()
-    {
-        foreach ($this->htmlAttributes as $attributeName => $attributeValue) {
-            if (strpos($attributeName, '-*') > 0) {
-                $prefix = substr($attributeName, 0, -1);
-                $this->wildcardPrefixes[] = $prefix;
-                unset($this->htmlAttributes[$attributeName]);
-            }
-        }
-    }
-
-    /**
-     * Overlay user defined html attribute values
-     * To determine whats a html attribute, the htmlAttributes
-     * array is used. If a html attribute value is found in userConfiguredElementTyposcript
-     * this value is set to htmlAttributes and removed from userConfiguredElementTyposcript.
-     *
-     * @return void
-     */
-    public function overlayUserdefinedHtmlAttributeValues()
-    {
-        foreach ($this->htmlAttributes as $attributeName => $attributeValue) {
-            $attributeNameWithoutDot = rtrim($attributeName, '.');
-            $attributeNameToSet = $attributeNameWithoutDot;
-
-            if ($this->arrayKeyExists($attributeNameWithoutDot, $this->userConfiguredElementTyposcript)) {
-                $attributeValue = $this->formBuilder->getFormUtility()->renderItem(
-                    $this->userConfiguredElementTyposcript[$attributeNameWithoutDot . '.'],
-                    $this->userConfiguredElementTyposcript[$attributeNameWithoutDot]
-                );
-                $this->htmlAttributes[$attributeNameToSet] = $attributeValue;
-            }
-
-            unset($this->userConfiguredElementTyposcript[$attributeNameWithoutDot . '.']);
-            unset($this->userConfiguredElementTyposcript[$attributeNameWithoutDot]);
-        }
-
-            // the prefix-* magic
-        $ignoreKeys = [];
-        foreach ($this->userConfiguredElementTyposcript as $attributeName => $attributeValue) {
-            // ignore child elements
-            if (
-                MathUtility::canBeInterpretedAsInteger($attributeName)
-                || isset($ignoreKeys[$attributeName])
-            ) {
-                $ignoreKeys[$attributeName . '.'] = true;
-                continue;
-            }
-
-            foreach ($this->wildcardPrefixes as $wildcardPrefix) {
-                if (strpos($attributeName, $wildcardPrefix) !== 0) {
-                    continue;
-                }
-                $attributeNameWithoutDot = rtrim($attributeName, '.');
-                $attributeValue = $this->formBuilder->getFormUtility()->renderItem(
-                    $this->userConfiguredElementTyposcript[$attributeNameWithoutDot . '.'],
-                    $this->userConfiguredElementTyposcript[$attributeNameWithoutDot]
-                );
-                $this->htmlAttributes[$attributeNameWithoutDot] = $attributeValue;
-                $ignoreKeys[$attributeNameWithoutDot . '.'] = true;
-                unset($this->userConfiguredElementTyposcript[$attributeNameWithoutDot . '.']);
-                unset($this->userConfiguredElementTyposcript[$attributeNameWithoutDot]);
-                break;
-            }
-        }
-    }
-
-    /**
-     * If fixedHtmlAttributeValues are defined for this element
-     * then overwrite the html attribute value
-     *
-     * @return void
-     */
-    public function overlayFixedHtmlAttributeValues()
-    {
-        $fixedHtmlAttributeValues = $this->typoScriptRepository->getModelConfigurationByScope($this->element->getElementType(), 'fixedHtmlAttributeValues.');
-        if (is_array($fixedHtmlAttributeValues)) {
-            foreach ($fixedHtmlAttributeValues as $attributeName => $attributeValue) {
-                $this->htmlAttributes[$attributeName] = $attributeValue;
-            }
-        }
-    }
-
-    /**
-     * Move htmlAttributes to additionalArguments that must be passed
-     * as a view helper argument
-     *
-     * @return void
-     */
-    public function moveHtmlAttributesToAdditionalArguments()
-    {
-        $htmlAttributesUsedByTheViewHelperDirectly = $this->typoScriptRepository->getModelConfigurationByScope($this->element->getElementType(), 'htmlAttributesUsedByTheViewHelperDirectly.');
-        if (is_array($htmlAttributesUsedByTheViewHelperDirectly)) {
-            foreach ($htmlAttributesUsedByTheViewHelperDirectly as $attributeName) {
-                if (array_key_exists($attributeName, $this->htmlAttributes)) {
-                    $this->additionalArguments[$attributeName] = $this->htmlAttributes[$attributeName];
-                    unset($this->htmlAttributes[$attributeName]);
-                }
-            }
-        }
-    }
-
-    /**
-     * Set the viewhelper default arguments in the additionalArguments array
-     *
-     * @return void
-     */
-    public function setViewHelperDefaulArgumentsToAdditionalArguments()
-    {
-        $viewHelperDefaultArguments = $this->typoScriptRepository->getModelConfigurationByScope($this->element->getElementType(), 'viewHelperDefaultArguments.');
-        if (is_array($viewHelperDefaultArguments)) {
-            foreach ($viewHelperDefaultArguments as $viewHelperDefaulArgumentName => $viewHelperDefaulArgumentValue) {
-                $viewHelperDefaulArgumentNameWithoutDot = rtrim($viewHelperDefaulArgumentName, '.');
-                $this->additionalArguments[$viewHelperDefaulArgumentNameWithoutDot] = $viewHelperDefaulArgumentValue;
-            }
-        }
-        unset($this->userConfiguredElementTyposcript['viewHelperDefaultArguments']);
-    }
-
-    /**
-     * Move all userdefined properties to the additionalArguments
-     * array. Ignore the child elements
-     *
-     * @return void
-     */
-    public function moveAllOtherUserdefinedPropertiesToAdditionalArguments()
-    {
-        $viewHelperDefaultArguments = $this->typoScriptRepository->getModelConfigurationByScope($this->element->getElementType(), 'viewHelperDefaultArguments.');
-        $ignoreKeys = [];
-
-        foreach ($this->userConfiguredElementTyposcript as $attributeName => $attributeValue) {
-            // ignore child elements
-            if (
-                MathUtility::canBeInterpretedAsInteger($attributeName)
-                || isset($ignoreKeys[$attributeName])
-                || $attributeName == 'postProcessor.'
-                || $attributeName == 'rules.'
-                || $attributeName == 'filters.'
-                || $attributeName == 'layout'
-            ) {
-                $ignoreKeys[$attributeName . '.'] = true;
-                continue;
-            }
-            $attributeNameWithoutDot = rtrim($attributeName, '.');
-            $attributeNameToSet = $attributeNameWithoutDot;
-
-            if (
-                isset($viewHelperDefaultArguments[$attributeName])
-                || isset($viewHelperDefaultArguments[$attributeNameWithoutDot])
-            ) {
-                $this->formBuilder->getFormUtility()->renderArrayItems($attributeValue);
-                $attributeValue = $this->typoScriptService->convertTypoScriptArrayToPlainArray($attributeValue);
-            } else {
-                $attributeValue = $this->formBuilder->getFormUtility()->renderItem(
-                    $this->userConfiguredElementTyposcript[$attributeNameWithoutDot . '.'],
-                    $this->userConfiguredElementTyposcript[$attributeNameWithoutDot]
-                );
-            }
-            $this->additionalArguments[$attributeNameToSet] = $attributeValue;
-            $ignoreKeys[$attributeNameToSet . '.'] = true;
-            $ignoreKeys[$attributeNameToSet] = true;
-
-            unset($this->userConfiguredElementTyposcript[$attributeNameWithoutDot . '.']);
-            unset($this->userConfiguredElementTyposcript[$attributeNameWithoutDot]);
-        }
-            // remove "stdWrap." from "additionalArguments" on
-            // the FORM Element
-        if (
-            !$this->formBuilder->getConfiguration()->getContentElementRendering()
-            && $this->element->getElementType() == 'FORM'
-        ) {
-            unset($this->additionalArguments['stdWrap']);
-            unset($this->additionalArguments['stdWrap.']);
-        }
-    }
-
-    /**
-     * Set the name and id attribute
-     *
-     * @return array
-     */
-    public function setNameAndId()
-    {
-        if (
-            $this->element->getParentElement()
-            && (int)$this->typoScriptRepository->getModelConfigurationByScope($this->element->getParentElement()->getElementType(), 'childrenInheritName') == 1
-        ) {
-            $this->htmlAttributes['name'] = $this->element->getParentElement()->getName();
-            $this->additionalArguments['multiple'] = '1';
-            $name = $this->sanitizeNameAttribute($this->userConfiguredElementTyposcript['name']);
-            $this->element->setName($name);
-        } else {
-            $this->htmlAttributes['name'] = $this->sanitizeNameAttribute($this->htmlAttributes['name']);
-            $this->element->setName($this->htmlAttributes['name']);
-        }
-        $this->htmlAttributes['id'] = $this->sanitizeIdAttribute($this->htmlAttributes['id']);
-        $this->element->setId($this->htmlAttributes['id']);
-    }
-
-    /**
-     * If the name is not defined it is automatically generated
-     * using the following syntax: id-{element_counter}
-     * The name attribute will be transformed if it contains some
-     * non allowed characters:
-     * - spaces are changed into hyphens
-     * - remove all characters except a-z A-Z 0-9 _ -
-     *
-     * @param string $name
-     * @return string
-     */
-    public function sanitizeNameAttribute($name)
-    {
-        $name = $this->formBuilder->getFormUtility()->sanitizeNameAttribute($name);
-        if (empty($name)) {
-            $name = 'id-' . $this->element->getElementCounter();
-        }
-        return $name;
-    }
-
-    /**
-     * If the id is not defined it is automatically generated
-     * using the following syntax: field-{element_counter}
-     * The id attribute will be transformed if it contains some
-     * non allowed characters:
-     * - spaces are changed into hyphens
-     * - if the id start with a integer then transform it to field-{integer}
-     * - remove all characters expect a-z A-Z 0-9 _ - : .
-     *
-     * @param string $id
-     * @return string
-     */
-    protected function sanitizeIdAttribute($id)
-    {
-        $id = $this->formBuilder->getFormUtility()->sanitizeIdAttribute($id);
-        if (empty($id)) {
-            $id = 'field-' . $this->element->getElementCounter();
-        }
-        return $id;
-    }
-
-    /**
-     * Check if a needle exists in a array.
-     *
-     * @param string $needle
-     * @param array $haystack
-     * @return bool TRUE if found
-     */
-    protected function arrayKeyExists($needle, array $haystack = [])
-    {
-        return
-            isset($haystack[$needle]) || isset($haystack[$needle . '.'])
-        ;
-    }
-
-    /**
-     * Get the current html attributes
-     *
-     * @return array
-     */
-    public function getHtmlAttributes()
-    {
-        return $this->htmlAttributes;
-    }
-
-    /**
-     * Set the current html attributes
-     *
-     * @param array $htmlAttributes
-     */
-    public function setHtmlAttributes(array $htmlAttributes)
-    {
-        $this->htmlAttributes = $htmlAttributes;
-    }
-
-    /**
-     * Get the current additional arguments
-     *
-     * @return array
-     */
-    public function getAdditionalArguments()
-    {
-        return $this->additionalArguments;
-    }
-
-    /**
-     * Set the current additional arguments
-     *
-     * @param array $additionalArguments
-     */
-    public function setAdditionalArguments(array $additionalArguments)
-    {
-        $this->additionalArguments = $additionalArguments;
-    }
-
-    /**
-     * Get the current wildcard prefixes
-     *
-     * @return array
-     */
-    public function getWildcardPrefixes()
-    {
-        return $this->wildcardPrefixes;
-    }
-
-    /**
-     * Set the current wildcard prefixes
-     *
-     * @param array $wildcardPrefixes
-     */
-    public function setWildcardPrefixes(array $wildcardPrefixes)
-    {
-        $this->wildcardPrefixes = $wildcardPrefixes;
-    }
-
-    /**
-     * Get the current Element
-     *
-     * @return array
-     */
-    public function getUserConfiguredElementTyposcript()
-    {
-        return $this->userConfiguredElementTyposcript;
-    }
-
-    /**
-     * Set the current Element
-     *
-     * @param array $userConfiguredElementTyposcript
-     */
-    public function setUserConfiguredElementTyposcript(array $userConfiguredElementTyposcript)
-    {
-        $this->userConfiguredElementTyposcript = $userConfiguredElementTyposcript;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Builder/FormBuilder.php b/typo3/sysext/form/Classes/Domain/Builder/FormBuilder.php
deleted file mode 100644
index 9f4ddac0ba683b6d548f41ed407b0a6de7d317dd..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Builder/FormBuilder.php
+++ /dev/null
@@ -1,579 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Builder;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\ArrayUtility;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Form\Domain\Model\Configuration;
-use TYPO3\CMS\Form\Domain\Model\Element;
-use TYPO3\CMS\Form\Domain\Model\ValidationElement;
-use TYPO3\CMS\Form\Mvc\Controller\ControllerContext;
-use TYPO3\CMS\Form\Utility\FormUtility;
-
-/**
- * TypoScript factory for form
- *
- * Takes the incoming TypoScript and adds all the necessary form objects
- * according to the configuration.
- */
-class FormBuilder
-{
-    /**
-     * @param Configuration $configuration
-     * @return FormBuilder
-     */
-    public static function create(Configuration $configuration)
-    {
-        /** @var FormBuilder $formBuilder */
-        $formBuilder = \TYPO3\CMS\Form\Utility\FormUtility::getObjectManager()->get(self::class);
-        $formBuilder->setConfiguration($configuration);
-        return $formBuilder;
-    }
-
-    /**
-     * @var FormUtility
-     */
-    protected $formUtility;
-
-    /**
-     * @var \TYPO3\CMS\Extbase\Service\TypoScriptService
-     */
-    protected $typoScriptService;
-
-    /**
-     * @var ValidationBuilder
-     */
-    protected $validationBuilder;
-
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository
-     */
-    protected $typoScriptRepository;
-
-    /**
-      * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
-      */
-    protected $signalSlotDispatcher;
-
-    /**
-     * @var \TYPO3\CMS\Form\Utility\SessionUtility
-     */
-    protected $sessionUtility;
-
-    /**
-     * @var \TYPO3\CMS\Extbase\Object\ObjectManager
-     */
-    protected $objectManager;
-
-    /**
-     * @var \TYPO3\CMS\Form\Utility\ElementCounter
-     */
-    protected $elementCounter;
-
-    /**
-     * @var NULL|\TYPO3\CMS\Extbase\Error\Result
-     */
-    protected $validationErrors = null;
-
-    /**
-     * @var Configuration;
-     */
-    protected $configuration;
-
-    /**
-     * @var ControllerContext
-     */
-    protected $controllerContext;
-
-    /**
-     * @param \TYPO3\CMS\Extbase\Service\TypoScriptService $typoScriptService
-     * @return void
-     */
-    public function injectTypoScriptService(\TYPO3\CMS\Extbase\Service\TypoScriptService $typoScriptService)
-    {
-        $this->typoScriptService = $typoScriptService;
-    }
-
-    /**
-     * @param \TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository $typoScriptRepository
-     * @return void
-     */
-    public function injectTypoScriptRepository(\TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository $typoScriptRepository)
-    {
-        $this->typoScriptRepository = $typoScriptRepository;
-    }
-
-    /**
-     * @param \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher
-     * @return void
-     */
-    public function injectSignalSlotDispatcher(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher)
-    {
-        $this->signalSlotDispatcher = $signalSlotDispatcher;
-    }
-
-    /**
-     * @param \TYPO3\CMS\Form\Utility\SessionUtility $sessionUtility
-     * @return void
-     */
-    public function injectSessionUtility(\TYPO3\CMS\Form\Utility\SessionUtility $sessionUtility)
-    {
-        $this->sessionUtility = $sessionUtility;
-    }
-
-    /**
-     * @param \TYPO3\CMS\Form\Utility\ElementCounter $elementCounter
-     * @return void
-     */
-    public function injectElementCounter(\TYPO3\CMS\Form\Utility\ElementCounter $elementCounter)
-    {
-        $this->elementCounter = $elementCounter;
-    }
-
-    /**
-     * @param \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager
-     * @return void
-     */
-    public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManager $objectManager)
-    {
-        $this->objectManager = $objectManager;
-    }
-
-    /**
-     * @return Configuration
-     */
-    public function getConfiguration()
-    {
-        return $this->configuration;
-    }
-
-    /**
-     * @param Configuration $configuration
-     */
-    public function setConfiguration(Configuration $configuration)
-    {
-        $this->configuration = $configuration;
-    }
-
-    /**
-     * @return ControllerContext
-     */
-    public function getControllerContext()
-    {
-        return $this->controllerContext;
-    }
-
-    /**
-     * @param ControllerContext $controllerContext
-     */
-    public function setControllerContext(ControllerContext $controllerContext)
-    {
-        $this->controllerContext = $controllerContext;
-    }
-
-    /**
-     * @return FormUtility
-     */
-    public function getFormUtility()
-    {
-        return $this->formUtility;
-    }
-
-    /**
-     * @param FormUtility $formUtility
-     */
-    public function setFormUtility(FormUtility $formUtility)
-    {
-        $this->formUtility = $formUtility;
-    }
-
-    /**
-     * @return ValidationBuilder
-     */
-    public function getValidationBuilder()
-    {
-        return $this->validationBuilder;
-    }
-
-    /**
-     * @param ValidationBuilder $validationBuilder
-     */
-    public function setValidationBuilder(ValidationBuilder $validationBuilder)
-    {
-        $this->validationBuilder = $validationBuilder;
-    }
-
-    /**
-     * Build model from TypoScript
-     * Needed if more than one form exist at a page
-     *
-     * @return NULL|\TYPO3\CMS\Form\Domain\Model\Element The form object containing the child elements
-     */
-    public function buildModel()
-    {
-        $userConfiguredFormTypoScript = $this->configuration->getTypoScript();
-        $form = $this->createElementObject();
-        $this->reviveElement($form, $userConfiguredFormTypoScript, 'FORM');
-        $form->setThemeName($this->configuration->getThemeName());
-        return $form;
-    }
-
-    /**
-     * Create a element
-     *
-     * @return \TYPO3\CMS\Form\Domain\Model\Element
-     */
-    protected function createElementObject()
-    {
-        $element = GeneralUtility::makeInstance(Element::class);
-        return $element;
-    }
-
-    /**
-     * Revive the domain model of the accordant element.
-     *
-     * @param Element $element
-     * @param array $userConfiguredElementTypoScript The configuration array
-     * @param string $elementType The element type (e.g BUTTON)
-     * @return void
-     */
-    protected function reviveElement(Element $element, array $userConfiguredElementTypoScript, $elementType = '')
-    {
-        // @todo Check $userConfiguredElementTypoScript
-
-        $element->setElementType($elementType);
-        $element->setElementCounter($this->elementCounter->getElementId());
-
-        $elementBuilder = ElementBuilder::create($this, $element, $userConfiguredElementTypoScript);
-        $elementBuilder->setPartialPaths();
-        $elementBuilder->setVisibility();
-
-        if ($element->getElementType() == 'CONTENTELEMENT') {
-            $attributeValue = '';
-            if ($this->configuration->getContentElementRendering()) {
-                $attributeValue = $this->formUtility->renderItem(
-                    $userConfiguredElementTypoScript['cObj.'],
-                    $userConfiguredElementTypoScript['cObj']
-                );
-            }
-            $element->setAdditionalArguments([
-                'content' => $attributeValue,
-            ]);
-        } else {
-            $this->setAttributes($elementBuilder, $element, $userConfiguredElementTypoScript);
-            $userConfiguredElementTypoScript = $elementBuilder->getUserConfiguredElementTyposcript();
-            $this->setValidationMessages($element);
-
-            $this->signalSlotDispatcher->dispatch(
-                __CLASS__,
-                'txFormAfterElementCreation',
-                [$element, $this]
-            );
-                // create all child elements
-            $this->setChildElementsByIntegerKey($element, $userConfiguredElementTypoScript);
-        }
-    }
-
-    /**
-     * Rendering of a "numerical array" of Form objects from TypoScript
-     * Creates new object for each element found
-     *
-     * @param Element $element
-     * @param array $userConfiguredElementTypoScript The configuration array
-     * @return void
-     * @throws \InvalidArgumentException
-     */
-    protected function setChildElementsByIntegerKey(Element $element, array $userConfiguredElementTypoScript)
-    {
-        if (is_array($userConfiguredElementTypoScript)) {
-            $keys = ArrayUtility::filterAndSortByNumericKeys($userConfiguredElementTypoScript);
-            foreach ($keys as $key) {
-                if (
-                    (int)$key
-                    && strpos($key, '.') === false
-                ) {
-                    $elementType = $userConfiguredElementTypoScript[$key];
-                    if (isset($userConfiguredElementTypoScript[$key . '.'])) {
-                        $concreteChildElementTypoScript = $userConfiguredElementTypoScript[$key . '.'];
-                    } else {
-                        $concreteChildElementTypoScript = [];
-                    }
-                    $this->distinguishElementType($element, $concreteChildElementTypoScript, $elementType);
-                }
-            }
-        } else {
-            throw new \InvalidArgumentException('Container element with id=' . $element->getElementCounter() . ' has no configuration which means no children.', 1333754854);
-        }
-    }
-
-    /**
-     * Create and add element by type.
-     * If its not a registered form element
-     * try to render it as contentelement with the internal elementType
-     * CONTENTELEMENT
-     *
-     * @param Element $element
-     * @param array $userConfiguredElementTypoScript The configuration array
-     * @param string $elementType The element type (e.g BUTTON)
-     * @return void
-     */
-    protected function distinguishElementType(Element $element, array $userConfiguredElementTypoScript, $elementType = '')
-    {
-        if (in_array($elementType, $this->typoScriptRepository->getRegisteredElementTypes())) {
-            $this->addChildElement($element, $userConfiguredElementTypoScript, $elementType);
-        } elseif ($this->configuration->getContentElementRendering()) {
-            $contentObject = [
-                'cObj' => $elementType,
-                'cObj.' => $userConfiguredElementTypoScript
-            ];
-            $this->addChildElement($element, $contentObject, 'CONTENTELEMENT');
-        }
-    }
-
-    /**
-     * Add child object to this element
-     *
-     * @param Element $element
-     * @param array $userConfiguredElementTypoScript The configuration array
-     * @param string $elementType The element type (e.g BUTTON)
-     * @return void
-     */
-    protected function addChildElement(Element $element, array $userConfiguredElementTypoScript, $elementType = '')
-    {
-        $childElement = $this->createElementObject();
-        $childElement->setParentElement($element);
-        $element->addChildElement($childElement);
-        $this->reviveElement($childElement, $userConfiguredElementTypoScript, $elementType);
-    }
-
-    /**
-     * Set the htmlAttributes and the additionalAttributes
-     * Remap htmlAttributes to additionalAttributes if needed
-     *
-     * @param ElementBuilder $elementBuilder
-     * @param Element $element
-     * @return void
-     */
-    protected function setAttributes(ElementBuilder $elementBuilder, Element $element)
-    {
-        $htmlAttributes = $this->typoScriptRepository->getModelDefinedHtmlAttributes($element->getElementType());
-        $elementBuilder->setHtmlAttributes($htmlAttributes);
-        $elementBuilder->setHtmlAttributeWildcards();
-        $elementBuilder->overlayUserdefinedHtmlAttributeValues();
-        $elementBuilder->setNameAndId();
-        $elementBuilder->overlayFixedHtmlAttributeValues();
-        // remove all NULL values
-        $htmlAttributes = array_filter($elementBuilder->getHtmlAttributes());
-
-        $elementBuilder->setHtmlAttributes($htmlAttributes);
-        $elementBuilder->moveHtmlAttributesToAdditionalArguments();
-        $elementBuilder->setViewHelperDefaulArgumentsToAdditionalArguments();
-        $elementBuilder->moveAllOtherUserdefinedPropertiesToAdditionalArguments();
-        $htmlAttributes = $elementBuilder->getHtmlAttributes();
-        $userConfiguredElementTypoScript = $elementBuilder->getUserConfiguredElementTyposcript();
-        $additionalArguments = $elementBuilder->getAdditionalArguments();
-        $element->setHtmlAttributes($htmlAttributes);
-        $additionalArguments = $this->typoScriptService->convertTypoScriptArrayToPlainArray($additionalArguments);
-        $additionalArguments['prefix'] = $this->configuration->getPrefix();
-        $element->setAdditionalArguments($additionalArguments);
-        $this->handleIncomingValues($element, $userConfiguredElementTypoScript);
-
-        if (
-            $element->getElementType() === 'FORM'
-            && $this->getControllerAction() === 'show'
-        ) {
-            if (empty($element->getHtmlAttribute('action'))) {
-                if (
-                    $element->getAdditionalArgument('confirmation')
-                    && (int)$element->getAdditionalArgument('confirmation') === 1
-                ) {
-                    $element->setAdditionalArgument('action', 'confirmation');
-                } else {
-                    $element->setAdditionalArgument('action', 'process');
-                }
-            } else {
-                $element->setAdditionalArgument('pageUid', $element->getHtmlAttribute('action'));
-                $element->setAdditionalArgument('action', null);
-            }
-        }
-
-        // needed if confirmation page is enabled
-        if (
-            $this->sessionUtility->getSessionData($element->getName())
-            && $element->getAdditionalArgument('uploadedFiles') === null
-        ) {
-            $element->setAdditionalArgument('uploadedFiles', $this->sessionUtility->getSessionData($element->getName()));
-        }
-    }
-
-    /**
-     * Handles the incoming form data
-     *
-     * @param Element $element
-     * @param array $userConfiguredElementTypoScript
-     * @return array
-     */
-    protected function handleIncomingValues(Element $element, array $userConfiguredElementTypoScript)
-    {
-        if (!$this->getIncomingData()) {
-            return;
-        }
-        $elementName = $element->getName();
-        if ($element->getHtmlAttribute('value') !== null) {
-            $modelValue = $element->getHtmlAttribute('value');
-        } else {
-            $modelValue = $element->getAdditionalArgument('value');
-        }
-
-        if ($this->getIncomingData()->getIncomingField($elementName) !== null) {
-            /* filter values and set it back to incoming fields */
-            $filters = isset($userConfiguredElementTypoScript['filters.']) ? $userConfiguredElementTypoScript['filters.'] : [];
-            if (!empty($filters)) {
-                $keys = ArrayUtility::filterAndSortByNumericKeys($filters);
-                foreach ($keys as $key) {
-                    $class = $userConfiguredElementTypoScript['filters.'][$key];
-                    if (
-                        (int)$key
-                        && strpos($key, '.') === false
-                    ) {
-                        $filterArguments = $userConfiguredElementTypoScript['filters.'][$key . '.'];
-                        $filterClassName = $this->typoScriptRepository->getRegisteredClassName((string)$class, 'registeredFilters');
-                        if ($filterClassName !== null) {
-                            // toDo: handel array values
-                            if (is_string($this->getIncomingData()->getIncomingField($elementName))) {
-                                if (is_null($filterArguments)) {
-                                    $filter = $this->objectManager->get($filterClassName);
-                                } else {
-                                    $filter = $this->objectManager->get($filterClassName, $filterArguments);
-                                }
-                                if ($filter) {
-                                    $value = $filter->filter($this->getIncomingData()->getIncomingField($elementName));
-                                    $this->getIncomingData()->setIncomingField($elementName, $value);
-                                } else {
-                                    throw new \RuntimeException('Class "' . $filterClassName . '" could not be loaded.', 1476122052);
-                                }
-                            }
-                        } else {
-                            throw new \RuntimeException('Class "' . $filterClassName . '" not registered via TypoScript.', 1476048485);
-                        }
-                    }
-                }
-            }
-
-            if ($element->getHtmlAttribute('value') !== null) {
-                $element->setHtmlAttribute('value', $this->getIncomingData()->getIncomingField($elementName));
-            } else {
-                $element->setAdditionalArgument('value', $this->getIncomingData()->getIncomingField($elementName));
-            }
-        }
-        $this->signalSlotDispatcher->dispatch(
-            __CLASS__,
-            'txFormHandleIncomingValues',
-            [
-                $element,
-                $this->getIncomingData(),
-                $modelValue,
-                $this
-            ]
-        );
-    }
-
-    /**
-     * Set the rendered mandatory message
-     * and the validation error message if available
-     *
-     * @param Element $element
-     * @return void
-     */
-    protected function setValidationMessages(Element $element)
-    {
-        $elementName = $element->getName();
-        $mandatoryMessages = $this->validationBuilder->getMandatoryValidationMessagesByElementName($elementName);
-        $element->setMandatoryValidationMessages($mandatoryMessages);
-        if (
-            $this->getValidationErrors()
-            && $this->getValidationErrors()->forProperty($elementName)->hasErrors()
-        ) {
-            /** @var \TYPO3\CMS\Extbase\Error\Error[] $errors */
-            $errors = $this->getValidationErrors()->forProperty($elementName)->getErrors();
-            $errorMessages = [];
-            foreach ($errors as $error) {
-                $errorMessages[] = $error->getMessage();
-            }
-            $element->setValidationErrorMessages($errorMessages);
-        }
-    }
-
-    /**
-     * Return the form prefix
-     *
-     * @return string
-     */
-    public function getFormPrefix()
-    {
-        return $this->configuration->getPrefix();
-    }
-
-    /**
-     * TRUE if the content element rendering should be disabled.
-     *
-     * @return bool
-     */
-    public function getDisableContentElementRendering()
-    {
-        return !$this->configuration->getContentElementRendering();
-    }
-
-    /**
-     * TRUE if the content element rendering should be disabled.
-     *
-     * @return string
-     */
-    public function getControllerAction()
-    {
-        return $this->controllerContext->getRequest()->getControllerActionName();
-    }
-
-    /**
-     * Get the incoming flat form data
-     *
-     * @return ValidationElement
-     */
-    public function getIncomingData()
-    {
-        return $this->controllerContext->getValidationElement();
-    }
-
-    /**
-     * Set the validation errors
-     *
-     * @param \TYPO3\CMS\Extbase\Error\Result $validationErrors
-     * @return void
-     */
-    public function setValidationErrors(\TYPO3\CMS\Extbase\Error\Result $validationErrors)
-    {
-        $this->validationErrors = $validationErrors;
-    }
-
-    /**
-     * Get the validation errors
-     *
-     * @return NULL|\TYPO3\CMS\Extbase\Error\Result
-     */
-    public function getValidationErrors()
-    {
-        return $this->validationErrors;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Builder/ValidationBuilder.php b/typo3/sysext/form/Classes/Domain/Builder/ValidationBuilder.php
deleted file mode 100644
index f56bccc9365b4615234b81215120b6f9cad5f2f8..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Builder/ValidationBuilder.php
+++ /dev/null
@@ -1,254 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Builder;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\ArrayUtility;
-use TYPO3\CMS\Form\Domain\Model\Configuration;
-use TYPO3\CMS\Form\Domain\Validator\AbstractValidator;
-use TYPO3\CMS\Form\Utility\FormUtility;
-
-/**
- * Parse and hole all the validation rules
- */
-class ValidationBuilder
-{
-    /**
-     * @param Configuration $configuration
-     * @return ValidationBuilder
-     */
-    public static function create(Configuration $configuration)
-    {
-        /** @var ValidationBuilder $validationBuilder */
-        $validationBuilder = \TYPO3\CMS\Form\Utility\FormUtility::getObjectManager()->get(self::class);
-        $validationBuilder->setConfiguration($configuration);
-        return $validationBuilder;
-    }
-
-    /**
-     * @var array|array[]
-     */
-    protected $rules = [];
-
-    /**
-     * @var string
-     */
-    protected $formPrefix = '';
-
-    /**
-     * @var \TYPO3\CMS\Extbase\Object\ObjectManager
-     */
-    protected $objectManager;
-
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository
-     */
-    protected $typoScriptRepository;
-
-    /**
-     * @var FormUtility
-     */
-    protected $formUtility;
-
-    /**
-     * @var Configuration
-     */
-    protected $configuration;
-
-    /**
-     * @param \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager
-     * @return void
-     */
-    public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManager $objectManager)
-    {
-        $this->objectManager = $objectManager;
-    }
-
-    /**
-     * @param \TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository $typoScriptRepository
-     * @return void
-     */
-    public function injectTypoScriptRepository(\TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository $typoScriptRepository)
-    {
-        $this->typoScriptRepository = $typoScriptRepository;
-    }
-
-    /**
-     * @param Configuration $configuration
-     */
-    public function setConfiguration(Configuration $configuration)
-    {
-        $this->configuration = $configuration;
-    }
-
-    /**
-     * @param FormUtility $formUtility
-     */
-    public function setFormUtility(FormUtility $formUtility)
-    {
-        $this->formUtility = $formUtility;
-    }
-
-    /**
-     * Build validation rules from typoscript.
-     * The old breakOnError property are no longer supported
-     *
-     * @param array $rawArgument
-     * @return void
-     */
-    public function buildRules(array $rawArgument = [])
-    {
-        $userConfiguredFormTyposcript = $this->configuration->getTypoScript();
-        $rulesTyposcript = isset($userConfiguredFormTyposcript['rules.']) ? $userConfiguredFormTyposcript['rules.'] : null;
-        $this->rules[$this->configuration->getPrefix()] = [];
-        if (is_array($rulesTyposcript)) {
-            $keys = ArrayUtility::filterAndSortByNumericKeys($rulesTyposcript);
-            foreach ($keys as $key) {
-                $ruleName = $rulesTyposcript[$key];
-                $validatorClassName = $this->typoScriptRepository->getRegisteredClassName($ruleName, 'registeredValidators');
-                if ($validatorClassName === null) {
-                    throw new \RuntimeException(
-                        'Class "' . $validatorClassName . '" not registered via typoscript.',
-                        1476048511
-                    );
-                }
-                if (
-                    (int)$key
-                    && strpos($key, '.') === false
-                ) {
-                    $ruleArguments = $rulesTyposcript[$key . '.'];
-                    $fieldName = $this->formUtility->sanitizeNameAttribute($ruleArguments['element']);
-                        // remove unsupported validator options
-                    $validatorOptions = $ruleArguments;
-                    $validatorOptions['errorMessage'] = [$ruleArguments['error.'], $ruleArguments['error']];
-                    $keysToRemove = array_flip([
-                        'breakOnError',
-                        'message',
-                        'message.',
-                        'error',
-                        'error.',
-                        'showMessage',
-                    ]);
-                    $validatorOptions = array_diff_key($validatorOptions, $keysToRemove);
-
-                    // Instantiate the validator to check if all required options are assigned
-                    // and to use the validator message rendering function to pre-render the mandatory message
-                    /** @var AbstractValidator $validator */
-                    $validator = $this->objectManager->get($validatorClassName, $validatorOptions);
-
-                    if ($validator instanceof AbstractValidator) {
-                        $validator->setRawArgument($rawArgument);
-                        $validator->setFormUtility($this->formUtility);
-
-                        if ((int)$ruleArguments['showMessage'] === 1) {
-                            $mandatoryMessage = $validator->renderMessage($ruleArguments['message.'], $ruleArguments['message']);
-                        } else {
-                            $mandatoryMessage = null;
-                        }
-
-                        $this->rules[$this->configuration->getPrefix()][$fieldName][] = [
-                            'validator' => $validator,
-                            'validatorName' => $validatorClassName,
-                            'validatorOptions' => $validatorOptions,
-                            'mandatoryMessage' => $mandatoryMessage
-                        ];
-                    } else {
-                        throw new \RuntimeException(
-                            'Class "' . $validatorClassName . '" could not be loaded.',
-                            1476048550
-                        );
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Set all validation rules
-     *
-     * @param array $rules
-     * @return void
-     */
-    public function setRules(array $rules)
-    {
-        $this->rules = $rules[$this->configuration->getPrefix()];
-    }
-
-    /**
-     * Get all validation rules
-     *
-     * @return array
-     */
-    public function getRules()
-    {
-        return $this->rules[$this->configuration->getPrefix()];
-    }
-
-    /**
-     * Set a validation rule
-     *
-     * @param string $key
-     * @param array $rule
-     * @return void
-     */
-    public function setRulesByElementName($key = '', array $rule = [])
-    {
-        $this->rules[$this->configuration->getPrefix()][$key] = $rule;
-    }
-
-    /**
-     * Get a validation rule by key
-     *
-     * @param string $key
-     * @return NULL|array
-     */
-    public function getRulesByElementName($key = '')
-    {
-        if (isset($this->rules[$this->configuration->getPrefix()][$key])) {
-            return $this->rules[$this->configuration->getPrefix()][$key];
-        }
-        return null;
-    }
-
-    /**
-     * Remove a validation rule by key
-     *
-     * @param string $key
-     * @return void
-     */
-    public function removeRule($key = '')
-    {
-        unset($this->rules[$this->configuration->getPrefix()][$key]);
-    }
-
-    /**
-     * Get all mandatory validation messages for a element
-     *
-     * @param string $key
-     * @return array
-     */
-    public function getMandatoryValidationMessagesByElementName($key = '')
-    {
-        $mandatoryMessages = [];
-        if ($this->getRulesByElementName($key)) {
-            $rules = $this->getRulesByElementName($key);
-            foreach ($rules as $rule) {
-                if ($rule['mandatoryMessage']) {
-                    $mandatoryMessages[] = $rule['mandatoryMessage'];
-                }
-            }
-        }
-        return $mandatoryMessages;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Configuration/ConfigurationService.php b/typo3/sysext/form/Classes/Domain/Configuration/ConfigurationService.php
new file mode 100644
index 0000000000000000000000000000000000000000..555e7956593b3859df7170d7c66eb095e2029481
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Configuration/ConfigurationService.php
@@ -0,0 +1,61 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Configuration;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Form\Domain\Configuration\Exception\PrototypeNotFoundException;
+use TYPO3\CMS\Form\Mvc\Configuration\ConfigurationManagerInterface;
+
+/**
+ * Helper for configuration settings
+ *
+ * Scope: frontend / backend
+ */
+class ConfigurationService
+{
+
+    /**
+     * @var array
+     */
+    protected $formSettings;
+
+    /**
+     * @internal
+     */
+    public function initializeObject()
+    {
+        $this->formSettings = GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(ConfigurationManagerInterface::class)
+            ->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_YAML_SETTINGS, 'form');
+    }
+
+     /**
+      * Get the prototype configuration
+      *
+      * @param string $prototypeName name of the prototype to get the configuration for
+      * @return array the prototype configuration
+      * @throws PrototypeNotFoundException if prototype with the name $prototypeName was not found
+      * @api
+      */
+     public function getPrototypeConfiguration(string $prototypeName): array
+     {
+         if (!isset($this->formSettings['prototypes'][$prototypeName])) {
+             throw new PrototypeNotFoundException(sprintf('The Prototype "%s" was not found.', $prototypeName), 1475924277);
+         }
+         return $this->formSettings['prototypes'][$prototypeName];
+     }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Filter/StripNewLinesFilter.php b/typo3/sysext/form/Classes/Domain/Configuration/Exception/PrototypeNotFoundException.php
similarity index 55%
rename from typo3/sysext/form/Classes/Domain/Filter/StripNewLinesFilter.php
rename to typo3/sysext/form/Classes/Domain/Configuration/Exception/PrototypeNotFoundException.php
index 66eca1dd192f05a7ae1a67d31cd25f5e9b33dcb8..90c311f53c222e0741f341f0669ca9795a067f90 100644
--- a/typo3/sysext/form/Classes/Domain/Filter/StripNewLinesFilter.php
+++ b/typo3/sysext/form/Classes/Domain/Configuration/Exception/PrototypeNotFoundException.php
@@ -1,5 +1,6 @@
 <?php
-namespace TYPO3\CMS\Form\Domain\Filter;
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Configuration\Exception;
 
 /*
  * This file is part of the TYPO3 CMS project.
@@ -14,19 +15,13 @@ namespace TYPO3\CMS\Form\Domain\Filter;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Form\Domain\Exception;
+
 /**
- * Strip new lines filter
+ * This exception is thrown if a form prototype for a given name was not found.
+ *
+ * @api
  */
-class StripNewLinesFilter extends AbstractFilter implements FilterInterface
+class PrototypeNotFoundException extends Exception
 {
-    /**
-     * Strip newlines
-     *
-     * @param string $value
-     * @return string
-     */
-    public function filter($value)
-    {
-        return str_replace([CRLF, LF, CR], ' ', (string)$value);
-    }
 }
diff --git a/typo3/sysext/form/Classes/Domain/Filter/FilterInterface.php b/typo3/sysext/form/Classes/Domain/Exception.php
similarity index 66%
rename from typo3/sysext/form/Classes/Domain/Filter/FilterInterface.php
rename to typo3/sysext/form/Classes/Domain/Exception.php
index 06222269ed79aa8fa12f777d7f4da944956db129..0fd7c4652cdb3684e79e17a277ac20709af0bce3 100644
--- a/typo3/sysext/form/Classes/Domain/Filter/FilterInterface.php
+++ b/typo3/sysext/form/Classes/Domain/Exception.php
@@ -1,5 +1,6 @@
 <?php
-namespace TYPO3\CMS\Form\Domain\Filter;
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain;
 
 /*
  * This file is part of the TYPO3 CMS project.
@@ -14,16 +15,13 @@ namespace TYPO3\CMS\Form\Domain\Filter;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Form\Exception as FormException;
+
 /**
- * Interface for filters
+ * A generic Form domain Exception
+ *
+ * @api
  */
-interface FilterInterface
+class Exception extends FormException
 {
-    /**
-     * Return filtered value
-     *
-     * @param mixed $value
-     * @return mixed
-     */
-    public function filter($value);
 }
diff --git a/typo3/sysext/form/Classes/Domain/Filter/LowerCaseFilter.php b/typo3/sysext/form/Classes/Domain/Exception/IdentifierNotValidException.php
similarity index 55%
rename from typo3/sysext/form/Classes/Domain/Filter/LowerCaseFilter.php
rename to typo3/sysext/form/Classes/Domain/Exception/IdentifierNotValidException.php
index 55c16d470042a30e25ada2058c8bf21d8d224373..8b5d257996f51c31c3cb518ba73e9825c27b6be8 100644
--- a/typo3/sysext/form/Classes/Domain/Filter/LowerCaseFilter.php
+++ b/typo3/sysext/form/Classes/Domain/Exception/IdentifierNotValidException.php
@@ -1,5 +1,6 @@
 <?php
-namespace TYPO3\CMS\Form\Domain\Filter;
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Exception;
 
 /*
  * This file is part of the TYPO3 CMS project.
@@ -14,19 +15,14 @@ namespace TYPO3\CMS\Form\Domain\Filter;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Form\Domain\Exception;
+
 /**
- * Lowercase filter
+ * This exception is thrown if the "identifier" for a Form, a Page or a Form Element
+ * is invalid (i.e. empty or not a string)
+ *
+ * @api
  */
-class LowerCaseFilter extends AbstractFilter implements FilterInterface
+class IdentifierNotValidException extends Exception
 {
-    /**
-     * Convert alphabetic characters to lowercase
-     *
-     * @param string $value
-     * @return string
-     */
-    public function filter($value)
-    {
-        return $this->convertCase($value, 'toLower');
-    }
 }
diff --git a/typo3/sysext/form/Classes/Domain/Exception/RenderingException.php b/typo3/sysext/form/Classes/Domain/Exception/RenderingException.php
new file mode 100644
index 0000000000000000000000000000000000000000..1430f8a06089cccf0447e37305bb63270da13614
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Exception/RenderingException.php
@@ -0,0 +1,27 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Exception;
+
+/**
+ * This exception is thrown if a rendering error occurs
+ *
+ * @api
+ */
+class RenderingException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Domain/Exception/TypeDefinitionNotFoundException.php b/typo3/sysext/form/Classes/Domain/Exception/TypeDefinitionNotFoundException.php
new file mode 100644
index 0000000000000000000000000000000000000000..3600a2adf9946089e81a194ca6470d4e5cd2b1b0
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Exception/TypeDefinitionNotFoundException.php
@@ -0,0 +1,28 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Exception;
+
+/**
+ * This exception is thrown if a Type Definition for a form element was not found,
+ * or if the implementationClassName was not set.
+ *
+ * @api
+ */
+class TypeDefinitionNotFoundException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Domain/Exception/TypeDefinitionNotValidException.php b/typo3/sysext/form/Classes/Domain/Exception/TypeDefinitionNotValidException.php
new file mode 100644
index 0000000000000000000000000000000000000000..70b58a4f4d674aac776f89d49d097db1c75e032b
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Exception/TypeDefinitionNotValidException.php
@@ -0,0 +1,28 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Exception;
+
+/**
+ * This exception is thrown if a Type Definition for a form element was not valid,
+ * i.e. it has properties which are not supported.
+ *
+ * @api
+ */
+class TypeDefinitionNotValidException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Domain/Exception/UnknownCompositRenderableException.php b/typo3/sysext/form/Classes/Domain/Exception/UnknownCompositRenderableException.php
new file mode 100644
index 0000000000000000000000000000000000000000..9ac5c2071658b7d8b401c98f62f20ae72b8d8a7c
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Exception/UnknownCompositRenderableException.php
@@ -0,0 +1,28 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Exception;
+
+/**
+ * This exception is thrown if the ArrayFormFactory want to create child
+ * elements within a unknown composit renderable.
+ *
+ * @api
+ */
+class UnknownCompositRenderableException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Domain/Factory/AbstractFormFactory.php b/typo3/sysext/form/Classes/Domain/Factory/AbstractFormFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..60c9e26a517f478097f5bdaacaef54b72e3e9d08
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Factory/AbstractFormFactory.php
@@ -0,0 +1,65 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Factory;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Model\FormDefinition;
+
+/**
+ * Base class for custom *Form Factories*. A Form Factory is responsible for building
+ * a {@link TYPO3\CMS\Form\Domain\Model\FormDefinition}.
+ *
+ * {@inheritDoc}
+ *
+ * Example
+ * =======
+ *
+ * Generally, you should use this class as follows:
+ *
+ * <pre>
+ * class MyFooBarFactory extends AbstractFormFactory {
+ *   public function build(array $configuration, $prototypeName) {
+ *     $configurationService = GeneralUtility::makeInstance(ObjectManager::class)->get(ConfigurationService::class);
+ *     $prototypeConfiguration = $configurationService->getPrototypeConfiguration($prototypeName);
+ *     $formDefinition = GeneralUtility::makeInstance(ObjectManager::class)->get(FormDefinition::class, 'nameOfMyForm', $prototypeConfiguration);
+ *
+ *     // now, you should call methods on $formDefinition to add pages and form elements
+ *
+ *     return $formDefinition;
+ *   }
+ * }
+ * </pre>
+ *
+ * Scope: frontend / backend
+ * **This class is meant to be sub classed by developers.**
+ * @api
+ */
+abstract class AbstractFormFactory implements FormFactoryInterface
+{
+    /**
+     * Helper to be called by every AbstractFormFactory after everything has been built to trigger the "onBuildingFinished"
+     * template method on all form elements.
+     *
+     * @param FormDefinition $form
+     * @return void
+     * @api
+     */
+    protected function triggerFormBuildingFinished(FormDefinition $form)
+    {
+        foreach ($form->getRenderablesRecursively() as $renderable) {
+            $renderable->onBuildingFinished();
+        }
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Factory/ArrayFormFactory.php b/typo3/sysext/form/Classes/Domain/Factory/ArrayFormFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..4b08561b4b48246de2b27b833387a6cdf91d61b2
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Factory/ArrayFormFactory.php
@@ -0,0 +1,120 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Factory;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Form\Domain\Configuration\ConfigurationService;
+use TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException;
+use TYPO3\CMS\Form\Domain\Exception\UnknownCompositRenderableException;
+use TYPO3\CMS\Form\Domain\Model\FormDefinition;
+use TYPO3\CMS\Form\Domain\Model\FormElements\AbstractSection;
+use TYPO3\CMS\Form\Domain\Model\Renderable\CompositeRenderableInterface;
+
+/**
+ * A factory that creates a FormDefinition from an array
+ *
+ * Scope: frontend / backend
+ */
+class ArrayFormFactory extends AbstractFormFactory
+{
+
+    /**
+     * Build a form definition, depending on some configuration.
+     *
+     * @param array $configuration
+     * @param string $prototypeName
+     * @return FormDefinition
+     * @internal
+     */
+    public function build(array $configuration, string $prototypeName = null): FormDefinition
+    {
+        if (empty($prototypeName)) {
+            $prototypeName = isset($configuration['prototypeName']) ? $configuration['prototypeName'] : 'standard';
+        }
+        $persistenceIdentifier = (isset($configuration['persistenceIdentifier'])) ? $configuration['persistenceIdentifier'] : null;
+
+        $prototypeConfiguration = GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(ConfigurationService::class)
+            ->getPrototypeConfiguration($prototypeName);
+
+        $form = GeneralUtility::makeInstance(ObjectManager::class)->get(
+            FormDefinition::class,
+            $configuration['identifier'],
+            $prototypeConfiguration,
+            'Form',
+            $persistenceIdentifier
+        );
+        if (isset($configuration['renderables'])) {
+            foreach ($configuration['renderables'] as $pageConfiguration) {
+                $this->addNestedRenderable($pageConfiguration, $form);
+            }
+        }
+
+        unset($configuration['persistenceIdentifier']);
+        unset($configuration['prototypeName']);
+        unset($configuration['renderables']);
+        unset($configuration['type']);
+        unset($configuration['identifier']);
+        unset($configuration['label']);
+        $form->setOptions($configuration);
+
+        $this->triggerFormBuildingFinished($form);
+
+        return $form;
+    }
+
+    /**
+     * Add form elements to the $parentRenderable
+     *
+     * @param array $nestedRenderableConfiguration
+     * @param CompositeRenderableInterface CompositeRenderableInterface $parentRenderable
+     * @return mixed
+     * @throws IdentifierNotValidException
+     * @throws UnknownCompositRenderableException
+     */
+    protected function addNestedRenderable(array $nestedRenderableConfiguration, CompositeRenderableInterface $parentRenderable)
+    {
+        if (!isset($nestedRenderableConfiguration['identifier'])) {
+            throw new IdentifierNotValidException('Identifier not set.', 1329289436);
+        }
+        if ($parentRenderable instanceof FormDefinition) {
+            $renderable = $parentRenderable->createPage($nestedRenderableConfiguration['identifier'], $nestedRenderableConfiguration['type']);
+        } elseif ($parentRenderable instanceof AbstractSection) {
+            $renderable = $parentRenderable->createElement($nestedRenderableConfiguration['identifier'], $nestedRenderableConfiguration['type']);
+        } else {
+            throw new UnknownCompositRenderableException('Unknown composit renderable "' . get_class($parentRenderable) . '"', 1479593622);
+        }
+
+        if (isset($nestedRenderableConfiguration['renderables']) && is_array($nestedRenderableConfiguration['renderables'])) {
+            $childRenderables = $nestedRenderableConfiguration['renderables'];
+        } else {
+            $childRenderables = [];
+        }
+
+        unset($nestedRenderableConfiguration['type']);
+        unset($nestedRenderableConfiguration['identifier']);
+        unset($nestedRenderableConfiguration['renderables']);
+
+        $renderable->setOptions($nestedRenderableConfiguration);
+
+        foreach ($childRenderables as $elementConfiguration) {
+            $this->addNestedRenderable($elementConfiguration, $renderable);
+        }
+
+        return $renderable;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Factory/FormFactoryInterface.php b/typo3/sysext/form/Classes/Domain/Factory/FormFactoryInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..1ccb06cfcba5490464d8b8c5c6a380cb5916a3ac
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Factory/FormFactoryInterface.php
@@ -0,0 +1,46 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Factory;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Model\FormDefinition;
+
+/**
+ * A Form Factory is responsible for building a {@link TYPO3\CMS\Form\Domain\Model\FormDefinition}.
+ * **Instead of implementing this interface, subclassing {@link AbstractFormFactory} is more appropriate
+ * in most cases**.
+ *
+ * A Form Factory can be called anytime a FormDefinition should be built; in most cases
+ * it is done through an invocation of a Form Rendering ViewHelper.
+ *
+ * Scope: frontend / backend
+ * @api
+ */
+interface FormFactoryInterface
+{
+
+    /**
+     * Build a form definition, depending on some configuration.
+     *
+     * The configuration array is factory-specific; for example a YAML or JSON factory
+     * could retrieve the path to the YAML / JSON file via the configuration array.
+     *
+     * @param array $configuration factory-specific configuration array
+     * @param string $prototypeName The name of the "PrototypeName" to use; it is factory-specific to implement this.
+     * @return FormDefinition a newly built form definition
+     * @api
+     */
+    public function build(array $configuration, string $prototypeName = null): FormDefinition;
+}
diff --git a/typo3/sysext/form/Classes/Domain/Factory/JsonToTypoScript.php b/typo3/sysext/form/Classes/Domain/Factory/JsonToTypoScript.php
deleted file mode 100644
index b10f8a575b51805e98def0e83a6317ba2eb0941b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Factory/JsonToTypoScript.php
+++ /dev/null
@@ -1,591 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Factory;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Json to Typoscript converter
- *
- * Takes the incoming Json and converts it to Typoscipt
- */
-class JsonToTypoScript
-{
-    /**
-     * Internal counter for the elements
-     *
-     * @var int
-     */
-    protected $elementId = 0;
-
-    /**
-     * Storage for the validation rules
-     * In TypoScript they are set in the form, in the wizard on the elements
-     *
-     * @var array
-     */
-    protected $validationRules = [];
-
-    /**
-     * Internal counter for the validation rules
-     *
-     * @var int
-     */
-    protected $validationRulesCounter = 1;
-
-    /**
-     * Convert JSON to TypoScript
-     *
-     * First a TypoScript array is constructed,
-     * which will be converted to a formatted string
-     *
-     * @param string $json Json containing all configuration for the form
-     * @return string The typoscript for the form
-     */
-    public function convert($json)
-    {
-        $elements = json_decode((string)$json, true);
-        $typoscriptArray = [];
-        $typoscript = null;
-        $this->convertToTyposcriptArray($elements, $typoscriptArray);
-        if ($typoscriptArray['10.'] && is_array($typoscriptArray['10.']) && !empty($typoscriptArray['10.'])) {
-            $typoscript = $this->typoscriptArrayToString($typoscriptArray['10.']);
-        }
-        return $typoscript;
-    }
-
-    /**
-     * Converts the JSON array for each element to a TypoScript array
-     * and adds this Typoscript array to the parent
-     *
-     * @param array $elements The JSON array
-     * @param array $parent The parent element
-     * @param bool $childrenWithParentName Indicates if the children use the parent name
-     * @return void
-     */
-    protected function convertToTyposcriptArray(array $elements, array &$parent, $childrenWithParentName = false)
-    {
-        if (is_array($elements)) {
-            $elementCounter = 10;
-            foreach ($elements as $element) {
-                if ($element['xtype']) {
-                    $this->elementId++;
-                    switch ($element['xtype']) {
-                        case 'typo3-form-wizard-elements-basic-button':
-
-                        case 'typo3-form-wizard-elements-basic-checkbox':
-
-                        case 'typo3-form-wizard-elements-basic-fileupload':
-
-                        case 'typo3-form-wizard-elements-basic-hidden':
-
-                        case 'typo3-form-wizard-elements-basic-password':
-
-                        case 'typo3-form-wizard-elements-basic-radio':
-
-                        case 'typo3-form-wizard-elements-basic-reset':
-
-                        case 'typo3-form-wizard-elements-basic-select':
-
-                        case 'typo3-form-wizard-elements-basic-submit':
-
-                        case 'typo3-form-wizard-elements-basic-textarea':
-
-                        case 'typo3-form-wizard-elements-basic-textline':
-
-                        case 'typo3-form-wizard-elements-predefined-email':
-
-                        case 'typo3-form-wizard-elements-content-header':
-
-                        case 'typo3-form-wizard-elements-content-textblock':
-                            $this->getDefaultElementSetup($element, $parent, $elementCounter, $childrenWithParentName);
-                            break;
-                        case 'typo3-form-wizard-elements-basic-fieldset':
-
-                        case 'typo3-form-wizard-elements-predefined-name':
-                            $this->getDefaultElementSetup($element, $parent, $elementCounter);
-                            $this->getContainer($element, $parent, $elementCounter);
-                            break;
-                        case 'typo3-form-wizard-elements-predefined-checkboxgroup':
-
-                        case 'typo3-form-wizard-elements-predefined-radiogroup':
-                            $this->getDefaultElementSetup($element, $parent, $elementCounter);
-                            $this->getContainer($element, $parent, $elementCounter, true);
-                            break;
-                        case 'typo3-form-wizard-elements-basic-form':
-                            $this->getDefaultElementSetup($element, $parent, $elementCounter);
-                            $this->getContainer($element, $parent, $elementCounter);
-                            $this->getForm($element, $parent, $elementCounter);
-                            break;
-                        default:
-
-                    }
-                }
-                $elementCounter = $elementCounter + 10;
-            }
-        }
-    }
-
-    /**
-     * Called for elements are a container for other elements like FORM and FIELDSET
-     *
-     * @param array $element The JSON array for this element
-     * @param array $parent The parent element
-     * @param bool $childrenWithParentName Indicates if the children use the parent name
-     * @param int $elementCounter The element counter
-     * @return void
-     */
-    protected function getContainer(array $element, array &$parent, $elementCounter, $childrenWithParentName = false)
-    {
-        if ($element['elementContainer'] && $element['elementContainer']['items']) {
-            $this->convertToTyposcriptArray($element['elementContainer']['items'], $parent[$elementCounter . '.'], $childrenWithParentName);
-        }
-    }
-
-    /**
-     * Only called for the type FORM
-     *
-     * Adds the validation rules to the form. In the wizard they are added to
-     * each element. In this script the validation rules are stored in a
-     * separate array to add them to the form at a later point.
-     *
-     * @param array $element The JSON array for this element
-     * @param array $parent The parent element
-     * @param int $elementCounter The element counter
-     * @return void
-     */
-    protected function getForm(array $element, array &$parent, $elementCounter)
-    {
-        // @todo Put at the top of the form
-        if (!empty($this->validationRules)) {
-            $parent[$elementCounter . '.']['rules'] = $this->validationRules;
-        }
-    }
-
-    /**
-     * Called for each element
-     *
-     * Adds the content object type to the parent array and starts adding the
-     * configuration for the element
-     *
-     * @param array $element The JSON array for this element
-     * @param array $parent The parent element
-     * @param int $elementCounter The element counter
-     * @param bool $childrenWithParentName Indicates if the children use the parent name
-     * @return void
-     */
-    protected function getDefaultElementSetup(array $element, array &$parent, $elementCounter, $childrenWithParentName = false)
-    {
-        $contentObjectType = $this->getContentObjectType($element);
-        if (is_null($contentObjectType) === false) {
-            $parent[$elementCounter] = $contentObjectType;
-            $parent[$elementCounter . '.'] = [];
-            if ($element['configuration']) {
-                $this->setConfiguration($element, $parent, $elementCounter, $childrenWithParentName);
-            }
-        }
-    }
-
-    /**
-     * Returns the content object type which is related to the ExtJS xtype
-     *
-     * @param array $element The JSON array for this element
-     * @return string The Content Object Type
-     */
-    protected function getContentObjectType(array $element)
-    {
-        $contentObjectType = null;
-        $shortXType = str_replace('typo3-form-wizard-elements-', '', $element['xtype']);
-        list($category, $type) = explode('-', $shortXType);
-        switch ($category) {
-            case 'basic':
-                $contentObjectType = strtoupper($type);
-                break;
-            case 'predefined':
-                switch ($type) {
-                case 'checkboxgroup':
-
-                case 'radiogroup':
-                    $contentObjectType = strtoupper($type);
-                    break;
-                case 'email':
-                    $contentObjectType = 'TEXTLINE';
-                    break;
-                case 'name':
-                    $contentObjectType = 'FIELDSET';
-                }
-                break;
-            case 'content':
-                switch ($type) {
-                case 'header':
-
-                case 'textblock':
-                    $contentObjectType = strtoupper($type);
-                }
-            default:
-
-        }
-        return $contentObjectType;
-    }
-
-    /**
-     * Iterates over the various configuration settings and calls the
-     * appropriate function for each setting
-     *
-     * @param array $element The JSON array for this element
-     * @param array $parent The parent element
-     * @param int $elementCounter The element counter
-     * @param bool $childrenWithParentName Indicates if the children use the parent name
-     * @return void
-     */
-    protected function setConfiguration(array $element, array &$parent, $elementCounter, $childrenWithParentName = false)
-    {
-        foreach ($element['configuration'] as $key => $value) {
-            switch ($key) {
-                case 'attributes':
-                    $this->setAttributes($value, $parent, $elementCounter, $childrenWithParentName);
-                    break;
-                case 'confirmation':
-                    $this->setConfirmation($value, $parent, $elementCounter);
-                    break;
-                case 'filters':
-                    $this->setFilters($value, $parent, $elementCounter);
-                    break;
-                case 'label':
-                    $this->setLabel($value, $parent, $elementCounter);
-                    break;
-                case 'layout':
-                    $this->setLayout($element, $value, $parent, $elementCounter);
-                    break;
-                case 'legend':
-                    $this->setLegend($value, $parent, $elementCounter);
-                    break;
-                case 'options':
-                    $this->setOptions($element, $value, $parent, $elementCounter);
-                    break;
-                case 'postProcessor':
-                    $this->setPostProcessor($value, $parent, $elementCounter);
-                    break;
-                case 'prefix':
-                    $this->setPrefix($value, $parent, $elementCounter);
-                    break;
-                case 'validation':
-                    $this->setValidationRules($element, $value);
-                    break;
-                case 'various':
-                    $this->setVarious($element, $value, $parent, $elementCounter);
-                    break;
-                default:
-
-            }
-        }
-    }
-
-    /**
-     * Set the attributes for the element
-     *
-     * @param array $attributes The JSON array for the attributes of this element
-     * @param array $parent The parent element
-     * @param int $elementCounter The element counter
-     * @param bool $childrenWithParentName Indicates if the children use the parent name
-     * @return void
-     */
-    protected function setAttributes(array $attributes, array &$parent, $elementCounter, $childrenWithParentName = false)
-    {
-        foreach ($attributes as $key => $value) {
-            if ($key === 'name' && $value === '' && !$childrenWithParentName) {
-                $value = $this->elementId;
-            }
-            if ($value != '') {
-                $parent[$elementCounter . '.'][$key] = $value;
-            }
-        }
-    }
-
-    /**
-     * Set the confirmation for the element FORM
-     *
-     * The confirmation indicates a confirmation screen has to be displayed
-     *
-     * @param bool $confirmation TRUE when confirmation screen
-     * @param array $parent The parent element
-     * @param int $elementCounter The element counter
-     * @return void
-     */
-    protected function setConfirmation($confirmation, array &$parent, $elementCounter)
-    {
-        $parent[$elementCounter . '.']['confirmation'] = $confirmation;
-    }
-
-    /**
-     * Set the filters for the element
-     *
-     * @param array $filters The JSON array for the filters of this element
-     * @param array $parent The parent element
-     * @param int $elementCounter The element counter
-     * @return void
-     */
-    protected function setFilters(array $filters, array &$parent, $elementCounter)
-    {
-        if (!empty($filters)) {
-            $parent[$elementCounter . '.']['filters'] = [];
-            $filterCounter = 1;
-            foreach ($filters as $name => $filterConfiguration) {
-                $parent[$elementCounter . '.']['filters'][$filterCounter] = $name;
-                $parent[$elementCounter . '.']['filters'][$filterCounter . '.'] = $filterConfiguration;
-                $filterCounter++;
-            }
-        }
-    }
-
-    /**
-     * Set the label for the element
-     *
-     * @param array $label The JSON array for the label of this element
-     * @param array $parent The parent element
-     * @param int $elementCounter The element counter
-     * @return void
-     */
-    protected function setLabel(array $label, array &$parent, $elementCounter)
-    {
-        if ($label['value'] != '') {
-            $parent[$elementCounter . '.']['label.']['value'] = $label['value'];
-        }
-    }
-
-    /**
-     * Changes the layout of some elements when this has been set in the wizard
-     *
-     * The wizard only uses 'back' or 'front' to set the layout. The TypoScript
-     * of the form uses a XML notation for the position of the label to the
-     * field.
-     *
-     * @param array $element The JSON array for this element
-     * @param string $value The layout setting, back or front
-     * @param array $parent The parent element
-     * @param int $elementCounter The element counter
-     * @return void
-     */
-    protected function setLayout(array $element, $value, array &$parent, $elementCounter)
-    {
-        switch ($element['xtype']) {
-            case 'typo3-form-wizard-elements-basic-button':
-
-            case 'typo3-form-wizard-elements-basic-fileupload':
-
-            case 'typo3-form-wizard-elements-basic-password':
-
-            case 'typo3-form-wizard-elements-basic-reset':
-
-            case 'typo3-form-wizard-elements-basic-submit':
-
-            case 'typo3-form-wizard-elements-basic-textline':
-                if ($value === 'back') {
-                    $parent[$elementCounter . '.']['layout'] = '<input />' . LF . '<label />';
-                }
-                break;
-            case 'typo3-form-wizard-elements-basic-checkbox':
-
-            case 'typo3-form-wizard-elements-basic-radio':
-                if ($value === 'front') {
-                    $parent[$elementCounter . '.']['layout'] = '<label />' . LF . '<input />';
-                }
-                break;
-            case 'typo3-form-wizard-elements-basic-select':
-                if ($value === 'back') {
-                    $parent[$elementCounter . '.']['layout'] = '<select>' . LF . '<elements />' . LF . '</select>' . LF . '<label />';
-                }
-                break;
-            case 'typo3-form-wizard-elements-basic-textarea':
-                if ($value === 'back') {
-                    $parent[$elementCounter . '.']['layout'] = '<textarea />' . LF . '<label />';
-                }
-                break;
-            default:
-
-        }
-    }
-
-    /**
-     * Set the legend for the element
-     *
-     * @param array $legend The JSON array for the legend of this element
-     * @param array $parent The parent element
-     * @param int $elementCounter The element counter
-     * @return void
-     */
-    protected function setLegend(array $legend, array &$parent, $elementCounter)
-    {
-        if ($legend['value'] != '') {
-            $parent[$elementCounter . '.']['legend.']['value'] = $legend['value'];
-        }
-    }
-
-    /**
-     * Set the options for a SELECT
-     *
-     * Although other elements like CHECKBOXGROUP and RADIOGROUP are using the
-     * option setting as well, they act like containers and are handled
-     * differently
-     *
-     * @param array $element The JSON array for this element
-     * @param array $options The JSON array for the options of this element
-     * @param array $parent The parent element
-     * @param int $elementCounter The element counter
-     * @return void
-     */
-    protected function setOptions(array $element, array $options, array &$parent, $elementCounter)
-    {
-        if (is_array($options) && $element['xtype'] === 'typo3-form-wizard-elements-basic-select') {
-            $optionCounter = 10;
-            foreach ($options as $option) {
-                $parent[$elementCounter . '.'][$optionCounter] = 'OPTION';
-                $parent[$elementCounter . '.'][$optionCounter . '.']['text'] = $option['text'];
-                if (isset($option['attributes'])) {
-                    $parent[$elementCounter . '.'][$optionCounter . '.'] += $option['attributes'];
-                }
-                $optionCounter = $optionCounter + 10;
-            }
-        }
-    }
-
-    /**
-     * Set the post processors for the element
-     *
-     * @param array $postProcessors The JSON array for the post processors of this element
-     * @param array $parent The parent element
-     * @param int $elementCounter The element counter
-     * @return void
-     */
-    protected function setPostProcessor(array $postProcessors, array &$parent, $elementCounter)
-    {
-        if (!empty($postProcessors)) {
-            $parent[$elementCounter . '.']['postProcessor'] = [];
-            $postProcessorCounter = 1;
-            foreach ($postProcessors as $name => $postProcessorConfiguration) {
-                $parent[$elementCounter . '.']['postProcessor'][$postProcessorCounter] = $name;
-                $parent[$elementCounter . '.']['postProcessor'][$postProcessorCounter . '.'] = $postProcessorConfiguration;
-                $postProcessorCounter++;
-            }
-        }
-    }
-
-    /**
-     * Set the prefix for the element FORM
-     *
-     * The prefix will be used in the names of all elements in the form
-     *
-     * @param string $prefix The prefix for all element names
-     * @param array $parent The parent element
-     * @param int $elementCounter The element counter
-     * @return void
-     */
-    protected function setPrefix($prefix, array &$parent, $elementCounter)
-    {
-        $parent[$elementCounter . '.']['prefix'] = $prefix;
-    }
-
-    /**
-     * Stores the validation rules, set to the elements, in a temporary array
-     *
-     * In the wizard the validation rules are added to the element,
-     * in TypoScript they are added to the form.
-     *
-     * @param array $element The JSON array for this element
-     * @param array $validationRules The temporary storage array for the rules
-     * @return void
-     */
-    protected function setValidationRules(array $element, array $validationRules)
-    {
-        foreach ($validationRules as $name => $ruleConfiguration) {
-            if (isset($element['configuration']['attributes']['name']) && $element['configuration']['attributes']['name'] != '') {
-                $ruleConfiguration['element'] = $element['configuration']['attributes']['name'];
-            } elseif (isset($element['configuration']['various']['name']) && $element['configuration']['various']['name'] != '') {
-                $ruleConfiguration['element'] = $element['configuration']['various']['name'];
-            } else {
-                $ruleConfiguration['element'] = $this->elementId;
-            }
-            $this->validationRules[$this->validationRulesCounter] = $name;
-            $this->validationRules[$this->validationRulesCounter . '.'] = $ruleConfiguration;
-            $this->validationRulesCounter++;
-        }
-    }
-
-    /**
-     * Set the various configuration of an element
-     *
-     * @param array $element The JSON array for this element
-     * @param array $various The JSON array for the various options of this element
-     * @param array $parent The parent element
-     * @param int $elementCounter The element counter
-     * @return void
-     */
-    protected function setVarious(array $element, array $various, array &$parent, $elementCounter)
-    {
-        foreach ($various as $key => $value) {
-            switch ($key) {
-                case 'headingSize':
-
-                case 'content':
-
-                case 'text':
-
-                case 'name':
-                    $parent[$elementCounter . '.'][$key] = (string)$value;
-                    break;
-            }
-        }
-    }
-
-    /**
-     * Converts a TypoScript array to a formatted string
-     *
-     * Takes care of indentation, curly brackets and parentheses
-     *
-     * @param array $typoscriptArray The TypoScript array
-     * @param string $addKey Key which has underlying configuration
-     * @param int $tabCount The amount of tabs for indentation
-     * @return string The formatted TypoScript string
-     */
-    protected function typoscriptArrayToString(array $typoscriptArray, $addKey = '', $tabCount = -1)
-    {
-        $typoscript = '';
-        if ($addKey != '') {
-            $typoscript .= str_repeat(TAB, $tabCount) . str_replace('.', '', $addKey) . ' {' . LF;
-        }
-        $tabCount++;
-        foreach ($typoscriptArray as $key => $value) {
-            if (!is_array($value)) {
-                if (strstr($value, LF)) {
-                    $typoscript .= str_repeat(TAB, $tabCount) . $key . ' (' . LF;
-                    if ($key !== 'text') {
-                        $value = str_replace(LF, LF . str_repeat(TAB, ($tabCount + 1)), $value);
-                        $typoscript .= str_repeat(TAB, ($tabCount + 1)) . $value . LF;
-                    } else {
-                        $typoscript .= $value . LF;
-                    }
-                    $typoscript .= str_repeat(TAB, $tabCount) . ')' . LF;
-                } else {
-                    $typoscript .= str_repeat(TAB, $tabCount) . $key . ' = ' . $value . LF;
-                }
-            } else {
-                $typoscript .= $this->typoscriptArrayToString($value, $key, $tabCount);
-            }
-        }
-        if ($addKey != '') {
-            $tabCount--;
-            $typoscript .= str_repeat(TAB, $tabCount) . '}' . LF;
-        }
-        return $typoscript;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Filter/AbstractFilter.php b/typo3/sysext/form/Classes/Domain/Filter/AbstractFilter.php
deleted file mode 100644
index 073158e6818bba5035ed70debb75f22abdc505c1..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Filter/AbstractFilter.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-use TYPO3\CMS\Core\Charset\CharsetConverter;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-/**
- * Abstract class for filters.
- */
-abstract class AbstractFilter
-{
-    protected function convertCase($value, $case)
-    {
-        return $this->getCharsetConverter()->conv_case(
-            'utf-8',
-            $value,
-            $case
-        );
-    }
-
-    /**
-     * @return CharsetConverter
-     */
-    protected function getCharsetConverter()
-    {
-        return GeneralUtility::makeInstance(CharsetConverter::class);
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Filter/AlphabeticFilter.php b/typo3/sysext/form/Classes/Domain/Filter/AlphabeticFilter.php
deleted file mode 100644
index f9f529a3346724e91633d6ca386105a39baf17b7..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Filter/AlphabeticFilter.php
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Alphabetic filter
- */
-class AlphabeticFilter extends AbstractFilter implements FilterInterface
-{
-    /**
-     * Allow whitespace
-     *
-     * @var bool
-     */
-    protected $allowWhiteSpace;
-
-    /**
-     * Constructor
-     *
-     * @param array $arguments Filter configuration
-     */
-    public function __construct($arguments = [])
-    {
-        $this->setAllowWhiteSpace($arguments['allowWhiteSpace']);
-    }
-
-    /**
-     * Allow white space in the submitted value
-     *
-     * @param bool $allowWhiteSpace True if allowed
-     * @return void
-     */
-    public function setAllowWhiteSpace($allowWhiteSpace = true)
-    {
-        $this->allowWhiteSpace = (bool)$allowWhiteSpace;
-    }
-
-    /**
-     * Return filtered value
-     * Remove all but alphabetic characters
-     * Allow whitespace by choice
-     *
-     * @param string $value
-     * @return string
-     */
-    public function filter($value)
-    {
-        $whiteSpace = $this->allowWhiteSpace ? '\\s' : '';
-        $pattern = '/[^\pL' . $whiteSpace . ']/u';
-        return preg_replace($pattern, '', (string)$value);
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Filter/AlphanumericFilter.php b/typo3/sysext/form/Classes/Domain/Filter/AlphanumericFilter.php
deleted file mode 100644
index 0c8c2670c127b98602f5fd7c27bcdf2879d575af..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Filter/AlphanumericFilter.php
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Alphanumeric filter
- */
-class AlphanumericFilter extends AbstractFilter implements FilterInterface
-{
-    /**
-     * Allow whitespace
-     *
-     * @var bool
-     */
-    protected $allowWhiteSpace;
-
-    /**
-     * Constructor
-     *
-     * @param array $arguments Filter configuration
-     */
-    public function __construct($arguments = [])
-    {
-        $this->setAllowWhiteSpace($arguments['allowWhiteSpace']);
-    }
-
-    /**
-     * Allow white space in the submitted value
-     *
-     * @param bool $allowWhiteSpace True if allowed
-     * @return void
-     */
-    public function setAllowWhiteSpace($allowWhiteSpace = true)
-    {
-        $this->allowWhiteSpace = (bool)$allowWhiteSpace;
-    }
-
-    /**
-     * Return filtered value
-     * Remove all but alphabetic and numeric characters
-     * Allow whitespace by choice
-     *
-     * @param string $value
-     * @return string
-     */
-    public function filter($value)
-    {
-        $whiteSpace = $this->allowWhiteSpace ? '\\s' : '';
-        $pattern = '/[^\pL\d' . $whiteSpace . ']/u';
-        return preg_replace($pattern, '', (string)$value);
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Filter/CurrencyFilter.php b/typo3/sysext/form/Classes/Domain/Filter/CurrencyFilter.php
deleted file mode 100644
index 99ae3c229df0133980be8079a585e63cfbf51140..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Filter/CurrencyFilter.php
+++ /dev/null
@@ -1,109 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Currency filter
- */
-class CurrencyFilter extends AbstractFilter implements FilterInterface
-{
-    /**
-     * Separator between group of thousands
-     * Mostly dot, comma or whitespace
-     *
-     * @var string
-     */
-    protected $decimalsPoint;
-
-    /**
-     * Separator between group of thousands
-     * Mostly dot, comma or whitespace
-     *
-     * @var string
-     */
-    protected $thousandSeparator;
-
-    /**
-     * Constructor
-     *
-     * @param array $arguments Filter configuration
-     */
-    public function __construct($arguments = [])
-    {
-        $this->setDecimalsPoint($arguments['decimalPoint']);
-        $this->setThousandSeparator($arguments['thousandSeparator']);
-    }
-
-    /**
-     * Set the decimal point character
-     *
-     * @param string $decimalsPoint Character used for decimal point
-     * @return void
-     */
-    public function setDecimalsPoint($decimalsPoint = '.')
-    {
-        if (empty($decimalsPoint)) {
-            $this->decimalsPoint = '.';
-        } else {
-            $this->decimalsPoint = (string)$decimalsPoint;
-        }
-    }
-
-    /**
-     * Set the thousand separator character
-     *
-     * @param string $thousandSeparator Character used for thousand separator
-     * @return void
-     */
-    public function setThousandSeparator($thousandSeparator = ',')
-    {
-        if (empty($thousandSeparator)) {
-            $this->thousandSeparator = ',';
-        } elseif ($thousandSeparator === 'space') {
-            $this->thousandSeparator = ' ';
-        } elseif ($thousandSeparator === 'none') {
-            $this->thousandSeparator = '';
-        } else {
-            $this->thousandSeparator = (string)$thousandSeparator;
-        }
-    }
-
-    /**
-     * Change to float with 2 decimals
-     * Change the dot to comma if requested
-     *
-     * @param string $value
-     * @return string
-     */
-    public function filter($value)
-    {
-        $value = str_replace(
-            [
-                $this->thousandSeparator,
-                $this->decimalsPoint,
-            ],
-            [
-                '',
-                '.'
-            ],
-            (string)$value
-        );
-
-        // replace all non numeric characters, decimalPoint and negativ sign
-        $value = preg_replace('/[^0-9.-]/', '', $value);
-        $value = (double)$value;
-        return number_format($value, 2, $this->decimalsPoint, $this->thousandSeparator);
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Filter/RegExpFilter.php b/typo3/sysext/form/Classes/Domain/Filter/RegExpFilter.php
deleted file mode 100644
index aace6b2660899c61e9c63f95ca26e71f30e2777f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Filter/RegExpFilter.php
+++ /dev/null
@@ -1,61 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Regular expression filter
- */
-class RegExpFilter extends AbstractFilter implements FilterInterface
-{
-    /**
-     * Regular expression for filter
-     *
-     * @var bool
-     */
-    protected $regularExpression;
-
-    /**
-     * Constructor
-     *
-     * @param array $arguments Filter configuration
-     */
-    public function __construct(array $arguments = [])
-    {
-        $this->setRegularExpression($arguments['expression']);
-    }
-
-    /**
-     * Set the regular expression
-     *
-     * @param string $expression The regular expression
-     * @return void
-     */
-    public function setRegularExpression($expression)
-    {
-        $this->regularExpression = (string)$expression;
-    }
-
-    /**
-     * Return filtered value
-     * Remove all characters found in regular expression
-     *
-     * @param string $value
-     * @return string
-     */
-    public function filter($value)
-    {
-        return preg_replace($this->regularExpression, '', (string)$value);
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Filter/RemoveXssFilter.php b/typo3/sysext/form/Classes/Domain/Filter/RemoveXssFilter.php
deleted file mode 100644
index 0a97a2bc04fc778c7d8b947040c1de1813de4a54..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Filter/RemoveXssFilter.php
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-/**
- * Remove Cross Site Scripting filter
- *
- * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
- */
-class RemoveXssFilter extends AbstractFilter implements FilterInterface
-{
-    /**
-     * Return filtered value
-     * Removes potential XSS code from the input string.
-     *
-     * Using an external class by Travis Puderbaugh <kallahar@quickwired.com>
-     *
-     * @param string $value Unfiltered value
-     * @return string The filtered value
-     * @deprecated since TYPO3 v8, will be removed in TYPO3 v9
-     */
-    public function filter($value)
-    {
-        $value = stripslashes($value);
-        $value = html_entity_decode($value, ENT_QUOTES);
-        $filteredValue = GeneralUtility::removeXSS($value);
-        return $filteredValue;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Filter/TitleCaseFilter.php b/typo3/sysext/form/Classes/Domain/Filter/TitleCaseFilter.php
deleted file mode 100644
index 89ae0c4a287696753e40400c8c7c019fe7e29e68..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Filter/TitleCaseFilter.php
+++ /dev/null
@@ -1,33 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Title filter
- */
-class TitleCaseFilter extends AbstractFilter implements FilterInterface
-{
-    /**
-     * Convert alphabetic characters to title case
-     *
-     * @param string $value
-     * @return string
-     */
-    public function filter($value)
-    {
-        $lower = $this->convertCase($value, 'toLower');
-        return ucwords($lower);
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Filter/TrimFilter.php b/typo3/sysext/form/Classes/Domain/Filter/TrimFilter.php
deleted file mode 100644
index cf36b9d3437c1639b6ffd94d6dd2b9d192d75575..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Filter/TrimFilter.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Trim filter
- */
-class TrimFilter extends AbstractFilter implements FilterInterface
-{
-    /**
-     * Characters used by trim filter
-     *
-     * @var string
-     */
-    protected $characterList;
-
-    /**
-     * Constructor
-     *
-     * @param array $arguments Filter configuration
-     */
-    public function __construct(array $arguments = [])
-    {
-        $this->setCharacterList($arguments['characterList']);
-    }
-
-    /**
-     * Set the characters that need to be stripped from the
-     * beginning or the end of the input,
-     * in addition to the default trim characters
-     *
-     * @param string $characterList
-     * @return void
-     */
-    public function setCharacterList($characterList)
-    {
-        $this->characterList = $characterList;
-    }
-
-    /**
-     * Return filtered value
-     * Strip characters from the beginning and the end
-     *
-     * @param string $value
-     * @return string
-     */
-    public function filter($value)
-    {
-        if (
-            $this->characterList === null
-            || $this->characterList === ''
-        ) {
-            return trim((string)$value);
-        } else {
-            return trim((string)$value, $this->characterList);
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Filter/UpperCaseFilter.php b/typo3/sysext/form/Classes/Domain/Filter/UpperCaseFilter.php
deleted file mode 100644
index d24b96758d663ce1aad648137c3a30389e9dd682..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Filter/UpperCaseFilter.php
+++ /dev/null
@@ -1,32 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Uppercase filter
- */
-class UpperCaseFilter extends AbstractFilter implements FilterInterface
-{
-    /**
-     * Convert alphabetic characters to uppercase
-     *
-     * @param string $value
-     * @return string
-     */
-    public function filter($value)
-    {
-        return $this->convertCase($value, 'toUpper');
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Finishers/AbstractFinisher.php b/typo3/sysext/form/Classes/Domain/Finishers/AbstractFinisher.php
new file mode 100644
index 0000000000000000000000000000000000000000..f88c5187e3627ab5a48b10350f23530403c03d21
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Finishers/AbstractFinisher.php
@@ -0,0 +1,208 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Finishers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
+use TYPO3\CMS\Extbase\Utility\ArrayUtility;
+use TYPO3\CMS\Form\Service\TranslationService;
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+
+/**
+ * Finisher base class.
+ *
+ * Scope: frontend
+ * **This class is meant to be sub classed by developers**
+ */
+abstract class AbstractFinisher implements FinisherInterface
+{
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * @var string
+     */
+    protected $finisherIdentifier = '';
+
+    /**
+     * The options which have been set from the outside. Instead of directly
+     * accessing them, you should rather use parseOption().
+     *
+     * @var array
+     */
+    protected $options = [];
+
+    /**
+     * These are the default options of the finisher.
+     * Override them in your concrete implementation.
+     * Default options should not be changed from "outside"
+     *
+     * @var array
+     */
+    protected $defaultOptions = [];
+
+    /**
+     * @var \TYPO3\CMS\Form\Domain\Finishers\FinisherContext
+     */
+    protected $finisherContext;
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
+     * @internal
+     */
+    public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
+    {
+        $this->objectManager = $objectManager;
+    }
+
+    /**
+     * @param array $options configuration options in the format ['option1' => 'value1', 'option2' => 'value2', ...]
+     * @return void
+     * @api
+     */
+    public function setOptions(array $options)
+    {
+        $this->options = $options;
+    }
+
+    /**
+     * Sets a single finisher option (@see setOptions())
+     *
+     * @param string $optionName name of the option to be set
+     * @param mixed $optionValue value of the option
+     * @return void
+     * @api
+     */
+    public function setOption(string $optionName, $optionValue)
+    {
+        $this->options[$optionName] = $optionValue;
+    }
+
+    /**
+     * Executes the finisher
+     *
+     * @param FinisherContext $finisherContext The Finisher context that contains the current Form Runtime and Response
+     * @return void
+     * @api
+     */
+    final public function execute(FinisherContext $finisherContext)
+    {
+        $this->finisherIdentifier = (new \ReflectionClass($this))->getShortName();
+        $this->finisherContext = $finisherContext;
+        $this->executeInternal();
+    }
+
+    /**
+     * This method is called in the concrete finisher whenever self::execute() is called.
+     *
+     * Override and fill with your own implementation!
+     *
+     * @return void
+     * @api
+     */
+    abstract protected function executeInternal();
+
+    /**
+     * Read the option called $optionName from $this->options, and parse {...}
+     * as object accessors.
+     *
+     * Then translate the value.
+     *
+     * If $optionName was not found, the corresponding default option is returned (from $this->defaultOptions)
+     *
+     * @param string $optionName
+     * @return string|array|null
+     * @api
+     */
+    protected function parseOption(string $optionName)
+    {
+        if ($optionName === 'translation') {
+            return null;
+        }
+
+        $optionValue = ArrayUtility::getValueByPath($this->options, $optionName);
+        $defaultValue = ArrayUtility::getValueByPath($this->defaultOptions, $optionName);
+
+        if ($optionValue === null && $defaultValue !== null) {
+            $optionValue = $defaultValue;
+        }
+
+        if ($optionValue === null) {
+            return null;
+        }
+
+        if (is_array($optionValue)) {
+            return $optionValue;
+        }
+
+        $formRuntime = $this->finisherContext->getFormRuntime();
+        $optionToCompare = $optionValue;
+
+        // You can encapsulate a option value with {}.
+        // This enables you to access every getable property from the
+        // TYPO3\CMS\Form\Domain\Runtime.
+        //
+        // For example: {formState.formValues.<elemenIdentifier>}
+        // This is equal to "$formRuntime->getFormState()->getFormValues()[<elemenIdentifier>]"
+        $optionValue = preg_replace_callback('/{([^}]+)}/', function ($match) use ($formRuntime) {
+            return ObjectAccess::getPropertyPath($formRuntime, $match[1]);
+        }, $optionValue);
+
+        if ($optionToCompare === $optionValue) {
+
+            // This is just a shortcut for a {formState.formValues.<elementIdentifier>} notation.
+            // If one of the finisher option values is equal
+            // to a identifier from the form definition then
+            // the value of the submitted form element is used
+            // insteed.
+            // Lets say you have a textfield in your form with the
+            // identifier "Text1". If you put "Text1"
+            // in the email finisher option "subject" then the submited value
+            // from the "Text1" element is used as the email subject.
+            $formValues = $this->finisherContext->getFormValues();
+            if (!is_bool($optionValue) && array_key_exists($optionValue, $formValues)) {
+                $optionValue = $formRuntime[$optionValue];
+            }
+        }
+
+        if (isset($this->options['translation']['translationFile'])) {
+            $optionValue = TranslationService::getInstance()->translateFinisherOption(
+                $formRuntime,
+                $this->finisherIdentifier,
+                $optionName,
+                $optionValue,
+                $this->options['translation']
+            );
+        }
+
+        if (empty($optionValue)) {
+            if ($defaultValue !== null) {
+                $optionValue = $defaultValue;
+            }
+        }
+        return $optionValue;
+    }
+
+    /**
+     * @return TypoScriptFrontendController
+     */
+    protected function getTypoScriptFrontendController()
+    {
+        return $GLOBALS['TSFE'];
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Finishers/ClosureFinisher.php b/typo3/sysext/form/Classes/Domain/Finishers/ClosureFinisher.php
new file mode 100644
index 0000000000000000000000000000000000000000..b4d20cf73f66f325a3d04c08231532cf065b123a
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Finishers/ClosureFinisher.php
@@ -0,0 +1,64 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Finishers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Finishers\Exception\FinisherException;
+
+/**
+ * A simple finisher that invokes a closure when executed
+ *
+ * Usage:
+ * //...
+ * $closureFinisher = $this->objectManager->get(ClosureFinisher::class);
+ * $closureFinisher->setOption('closure', function($finisherContext) {
+ *   $formRuntime = $finisherContext->getFormRuntime();
+ *   // ...
+ * });
+ * $formDefinition->addFinisher($closureFinisher);
+ * // ...
+ *
+ * Scope: frontend
+ */
+class ClosureFinisher extends AbstractFinisher
+{
+
+    /**
+     * @var array
+     */
+    protected $defaultOptions = [
+        'closure' => null
+    ];
+
+    /**
+     * Executes this finisher
+     * @see AbstractFinisher::execute()
+     *
+     * @return void
+     * @throws FinisherException
+     */
+    protected function executeInternal()
+    {
+        /** @var $closure \Closure */
+        $closure = $this->parseOption('closure');
+        if ($closure === null) {
+            return;
+        }
+        if (!$closure instanceof \Closure) {
+            throw new FinisherException(sprintf('The option "closure" must be of type Closure, "%s" given.', gettype($closure)), 1332155239);
+        }
+        $closure($this->finisherContext);
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Finishers/ConfirmationFinisher.php b/typo3/sysext/form/Classes/Domain/Finishers/ConfirmationFinisher.php
new file mode 100644
index 0000000000000000000000000000000000000000..722dfbb171159af57b9b3b8e9056cfbf5e0e929e
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Finishers/ConfirmationFinisher.php
@@ -0,0 +1,63 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Finishers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Finishers\Exception\FinisherException;
+
+/**
+ * A simple finisher that outputs a given text
+ *
+ * Options:
+ *
+ * - message: A hard-coded message to be rendered
+ *
+ * Usage:
+ * //...
+ * $confirmationFinisher = $this->objectManager->get(ConfirmationFinisher::class);
+ * $confirmationFinisher->setOptions(
+ *   [
+ *     'message' => 'foo',
+ *   ]
+ * );
+ * $formDefinition->addFinisher($confirmationFinisher);
+ * // ...
+ *
+ * Scope: frontend
+ */
+class ConfirmationFinisher extends AbstractFinisher
+{
+
+    /**
+     * @var array
+     */
+    protected $defaultOptions = [
+        'message' => 'The form has been submitted.',
+    ];
+
+    /**
+     * Executes this finisher
+     * @see AbstractFinisher::execute()
+     *
+     * @return void
+     * @throws FinisherException
+     */
+    protected function executeInternal()
+    {
+        $formRuntime = $this->finisherContext->getFormRuntime();
+        $message = $this->parseOption('message');
+        $formRuntime->getResponse()->setContent($message);
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Finishers/DeleteUploadsFinisher.php b/typo3/sysext/form/Classes/Domain/Finishers/DeleteUploadsFinisher.php
new file mode 100644
index 0000000000000000000000000000000000000000..43dcd1363e94e86e27afe1a9289c799388c31778
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Finishers/DeleteUploadsFinisher.php
@@ -0,0 +1,57 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Finishers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Domain\Model\FileReference;
+use TYPO3\CMS\Form\Domain\Model\FormElements\FileUpload;
+
+/**
+ * This finisher remove the submited files.
+ * Use this e.g after the email finisher if you dont want
+ * to keep the files online.
+ *
+ * Scope: frontend
+ */
+class DeleteUploadsFinisher extends AbstractFinisher
+{
+
+    /**
+     * Executes this finisher
+     * @see AbstractFinisher::execute()
+     *
+     * @return void
+     */
+    protected function executeInternal()
+    {
+        $formRuntime = $this->finisherContext->getFormRuntime();
+
+        $elements = $formRuntime->getFormDefinition()->getRenderablesRecursively();
+        foreach ($elements as $element) {
+            if (!$element instanceof FileUpload) {
+                continue;
+            }
+            $file = $formRuntime[$element->getIdentifier()];
+            if (!$file) {
+                continue;
+            }
+
+            if ($file instanceof FileReference) {
+                $file = $file->getOriginalResource();
+            }
+            $file->getStorage()->deleteFile($file);
+        }
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Finishers/EmailFinisher.php b/typo3/sysext/form/Classes/Domain/Finishers/EmailFinisher.php
new file mode 100644
index 0000000000000000000000000000000000000000..c2070b49535f51b1fd93b8d95724192a1dc071d8
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Finishers/EmailFinisher.php
@@ -0,0 +1,187 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Finishers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Mail\MailMessage;
+use TYPO3\CMS\Extbase\Domain\Model\FileReference;
+use TYPO3\CMS\Fluid\View\StandaloneView;
+use TYPO3\CMS\Form\Domain\Finishers\Exception\FinisherException;
+use TYPO3\CMS\Form\Domain\Model\FormElements\FileUpload;
+use TYPO3\CMS\Form\Service\TranslationService;
+
+/**
+ * This finisher sends an email to one recipient
+ *
+ * Options:
+ *
+ * - templatePathAndFilename (mandatory): Template path and filename for the mail body
+ * - layoutRootPath: root path for the layouts
+ * - partialRootPath: root path for the partials
+ * - variables: associative array of variables which are available inside the Fluid template
+ *
+ * The following options control the mail sending. In all of them, placeholders in the form
+ * of {...} are replaced with the corresponding form value; i.e. {email} as recipientAddress
+ * makes the recipient address configurable.
+ *
+ * - subject (mandatory): Subject of the email
+ * - recipientAddress (mandatory): Email address of the recipient
+ * - recipientName: Human-readable name of the recipient
+ * - senderAddress (mandatory): Email address of the sender
+ * - senderName: Human-readable name of the sender
+ * - replyToAddress: Email address of to be used as reply-to email (use multiple addresses with an array)
+ * - carbonCopyAddress: Email address of the copy recipient (use multiple addresses with an array)
+ * - blindCarbonCopyAddress: Email address of the blind copy recipient (use multiple addresses with an array)
+ * - format: format of the email (one of the FORMAT_* constants). By default mails are sent as HTML
+ *
+ * Scope: frontend
+ */
+class EmailFinisher extends AbstractFinisher
+{
+    const FORMAT_PLAINTEXT = 'plaintext';
+    const FORMAT_HTML = 'html';
+
+    /**
+     * @var array
+     */
+    protected $defaultOptions = [
+        'recipientName' => '',
+        'senderName' => '',
+        'format' => self::FORMAT_HTML,
+        'attachUploads' => true
+    ];
+
+    /**
+     * Executes this finisher
+     * @see AbstractFinisher::execute()
+     *
+     * @return void
+     * @throws FinisherException
+     */
+    protected function executeInternal()
+    {
+        $formRuntime = $this->finisherContext->getFormRuntime();
+        $standaloneView = $this->initializeStandaloneView();
+        $standaloneView->assign('form', $formRuntime);
+
+        $translationService = TranslationService::getInstance();
+        if (isset($this->options['translation']['language']) && !empty($this->options['translation']['language'])) {
+            $languageBackup = $translationService->getLanguage();
+            $translationService->setLanguage($this->options['translation']['language']);
+        }
+        $message = $standaloneView->render();
+        if (!empty($languageBackup)) {
+            $translationService->setLanguage($languageBackup);
+        }
+
+        $subject = $this->parseOption('subject');
+        $recipientAddress = $this->parseOption('recipientAddress');
+        $recipientName = $this->parseOption('recipientName');
+        $senderAddress = $this->parseOption('senderAddress');
+        $senderName = $this->parseOption('senderName');
+        $replyToAddress = $this->parseOption('replyToAddress');
+        $carbonCopyAddress = $this->parseOption('carbonCopyAddress');
+        $blindCarbonCopyAddress = $this->parseOption('blindCarbonCopyAddress');
+        $format = $this->parseOption('format');
+        $attachUploads = $this->parseOption('attachUploads');
+
+        if (empty($subject)) {
+            throw new FinisherException('The option "subject" must be set for the EmailFinisher.', 1327060320);
+        }
+        if (empty($recipientAddress)) {
+            throw new FinisherException('The option "recipientAddress" must be set for the EmailFinisher.', 1327060200);
+        }
+        if (empty($senderAddress)) {
+            throw new FinisherException('The option "senderAddress" must be set for the EmailFinisher.', 1327060210);
+        }
+
+        $mail = $this->objectManager->get(MailMessage::class);
+
+        $mail->setFrom([$senderAddress => $senderName])
+            ->setTo([$recipientAddress => $recipientName])
+            ->setSubject($subject);
+
+        if (!empty($replyToAddress)) {
+            $mail->setReplyTo($replyToAddress);
+        }
+
+        if (!empty($carbonCopyAddress)) {
+            $mail->setCc($carbonCopyAddress);
+        }
+
+        if (!empty($blindCarbonCopyAddress)) {
+            $mail->setBcc($blindCarbonCopyAddress);
+        }
+
+        if ($format === self::FORMAT_PLAINTEXT) {
+            $mail->setBody($message, 'text/plain');
+        } else {
+            $mail->setBody($message, 'text/html');
+        }
+
+        $elements = $formRuntime->getFormDefinition()->getRenderablesRecursively();
+
+        if ($attachUploads) {
+            foreach ($elements as $element) {
+                if (!$element instanceof FileUpload) {
+                    continue;
+                }
+                $file = $formRuntime[$element->getIdentifier()];
+                if ($file) {
+                    if ($file instanceof FileReference) {
+                        $file = $file->getOriginalResource();
+                    }
+
+                    $mail->attach(\Swift_Attachment::newInstance($file->getContents(), $file->getName(), $file->getMimeType()));
+                }
+            }
+        }
+
+        $mail->send();
+    }
+
+    /**
+     * @return StandaloneView
+     * @throws FinisherException
+     */
+    protected function initializeStandaloneView(): StandaloneView
+    {
+        if (!isset($this->options['templatePathAndFilename'])) {
+            throw new FinisherException('The option "templatePathAndFilename" must be set for the EmailFinisher.', 1327058829);
+        }
+
+        $format = ucfirst($this->parseOption('format'));
+
+        $this->options['templatePathAndFilename'] = strtr($this->options['templatePathAndFilename'], [
+            '{@format}' => $format
+        ]);
+
+        $standaloneView = $this->objectManager->get(StandaloneView::class);
+        $standaloneView->setTemplatePathAndFilename($this->options['templatePathAndFilename']);
+
+        if (isset($this->options['partialRootPaths']) && is_array($this->options['partialRootPaths'])) {
+            $standaloneView->setPartialRootPaths($this->options['partialRootPaths']);
+        }
+
+        if (isset($this->options['layoutRootPaths']) && is_array($this->options['layoutRootPaths'])) {
+            $standaloneView->setLayoutRootPaths($this->options['layoutRootPaths']);
+        }
+
+        if (isset($this->options['variables'])) {
+            $standaloneView->assignMultiple($this->options['variables']);
+        }
+        return $standaloneView;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Finishers/Exception/FinisherException.php b/typo3/sysext/form/Classes/Domain/Finishers/Exception/FinisherException.php
new file mode 100644
index 0000000000000000000000000000000000000000..7464f2181088a720c85a035a5ad2fdcf5e0c95ac
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Finishers/Exception/FinisherException.php
@@ -0,0 +1,27 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Finishers\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Exception;
+
+/**
+ * This exception is thrown in Form Finishers
+ *
+ * @api
+ */
+class FinisherException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Domain/Finishers/FinisherContext.php b/typo3/sysext/form/Classes/Domain/Finishers/FinisherContext.php
new file mode 100644
index 0000000000000000000000000000000000000000..80a40fb0e961fcbcb6177dc7647a34ac37f88461
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Finishers/FinisherContext.php
@@ -0,0 +1,115 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Finishers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+
+/**
+ * The context that is passed to each finisher when executed.
+ * It acts like an EventObject that is able to stop propagation.
+ *
+ * Scope: frontend
+ * **This class is NOT meant to be sub classed by developers.**
+ * @internal
+ */
+class FinisherContext
+{
+
+    /**
+     * If TRUE further finishers won't be invoked
+     *
+     * @var bool
+     */
+    protected $cancelled = false;
+
+    /**
+     * A reference to the Form Runtime that the finisher belongs to
+     *
+     * @var \TYPO3\CMS\Form\Domain\Runtime\FormRuntime
+     */
+    protected $formRuntime;
+
+    /**
+     * The assigned controller context which might be needed by the finisher.
+     *
+     * @var \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext
+     */
+    protected $controllerContext;
+
+    /**
+     * @param FormRuntime $formRuntime
+     * @internal
+     */
+    public function __construct(FormRuntime $formRuntime, ControllerContext $controllerContext)
+    {
+        $this->formRuntime = $formRuntime;
+        $this->controllerContext = $controllerContext;
+    }
+
+    /**
+     * Cancels the finisher invocation after the current finisher
+     *
+     * @return void
+     * @api
+     */
+    public function cancel()
+    {
+        $this->cancelled = true;
+    }
+
+    /**
+     * TRUE if no futher finishers should be invoked. Defaults to FALSE
+     *
+     * @return bool
+     * @internal
+     */
+    public function isCancelled(): bool
+    {
+        return $this->cancelled;
+    }
+
+    /**
+     * The Form Runtime that is associated with the current finisher
+     *
+     * @return FormRuntime
+     * @api
+     */
+    public function getFormRuntime(): FormRuntime
+    {
+        return $this->formRuntime;
+    }
+
+    /**
+     * The values of the submitted form (after validation and property mapping)
+     *
+     * @return array
+     * @api
+     */
+    public function getFormValues(): array
+    {
+        return $this->formRuntime->getFormState()->getFormValues();
+    }
+
+    /**
+     * @return ControllerContext
+     * @api
+     */
+    public function getControllerContext(): ControllerContext
+    {
+        return $this->controllerContext;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Finishers/FinisherInterface.php b/typo3/sysext/form/Classes/Domain/Finishers/FinisherInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..c5c9683973a088da889213ae8321bbc33d958331
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Finishers/FinisherInterface.php
@@ -0,0 +1,52 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Finishers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Finisher that can be attached to a form in order to be invoked
+ * as soon as the complete form is submitted
+ *
+ * Scope: frontend
+ */
+interface FinisherInterface
+{
+
+    /**
+     * Executes the finisher
+     *
+     * @param FinisherContext $finisherContext The Finisher context that contains the current Form Runtime and Response
+     * @return void
+     * @api
+     */
+    public function execute(FinisherContext $finisherContext);
+
+    /**
+     * @param array $options configuration options in the format ['option1' => 'value1', 'option2' => 'value2', ...]
+     * @return void
+     * @api
+     */
+    public function setOptions(array $options);
+
+    /**
+     * Sets a single finisher option (@see setOptions())
+     *
+     * @param string $optionName name of the option to be set
+     * @param mixed $optionValue value of the option
+     * @return void
+     * @api
+     */
+    public function setOption(string $optionName, $optionValue);
+}
diff --git a/typo3/sysext/form/Classes/Domain/Finishers/FlashMessageFinisher.php b/typo3/sysext/form/Classes/Domain/Finishers/FlashMessageFinisher.php
new file mode 100644
index 0000000000000000000000000000000000000000..5856a0988fa03cf5ec302041b45cdc62ffce02e1
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Finishers/FlashMessageFinisher.php
@@ -0,0 +1,97 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Finishers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Messaging\AbstractMessage;
+use TYPO3\CMS\Core\Messaging\FlashMessage;
+use TYPO3\CMS\Extbase\Error\Error;
+use TYPO3\CMS\Extbase\Error\Message;
+use TYPO3\CMS\Extbase\Error\Notice;
+use TYPO3\CMS\Extbase\Error\Warning;
+use TYPO3\CMS\Form\Domain\Finishers\Exception\FinisherException;
+
+/**
+ * A simple finisher that adds a message to the FlashMessageContainer
+ *
+ * Usage:
+ * //...
+ * $flashMessageFinisher = $this->objectManager->get(FlashMessageFinisher::class);
+ * $flashMessageFinisher->setOptions(
+ *   [
+ *     'messageBody' => 'Some message body',
+ *     'messageTitle' => 'Some message title',
+ *     'messageArguments' => ['foo' => 'bar'],
+ *     'severity' => \TYPO3\CMS\Core\Messaging\AbstractMessage::ERROR
+ *   ]
+ * );
+ * $formDefinition->addFinisher($flashMessageFinisher);
+ * // ...
+ *
+ * Scope: frontend
+ */
+class FlashMessageFinisher extends AbstractFinisher
+{
+
+    /**
+     * @var array
+     */
+    protected $defaultOptions = [
+        'messageBody' => null,
+        'messageTitle' => '',
+        'messageArguments' => [],
+        'messageCode' => null,
+        'severity' => AbstractMessage::OK,
+    ];
+
+    /**
+     * Executes this finisher
+     * @see AbstractFinisher::execute()
+     *
+     * @return void
+     * @throws FinisherException
+     */
+    protected function executeInternal()
+    {
+        $messageBody = $this->parseOption('messageBody');
+        if (!is_string($messageBody)) {
+            throw new FinisherException(sprintf('The message body must be of type string, "%s" given.', gettype($messageBody)), 1335980069);
+        }
+        $messageTitle = $this->parseOption('messageTitle');
+        $messageArguments = $this->parseOption('messageArguments');
+        $messageCode = $this->parseOption('messageCode');
+        $severity = $this->parseOption('severity');
+        switch ($severity) {
+            case AbstractMessage::NOTICE:
+                $message = $this->objectManager->get(Notice::class, $messageBody, $messageCode, $messageArguments, $messageTitle);
+                break;
+            case AbstractMessage::WARNING:
+                $message = $this->objectManager->get(Warning::class, $messageBody, $messageCode, $messageArguments, $messageTitle);
+                break;
+            case AbstractMessage::ERROR:
+                $message = $this->objectManager->get(Error::class, $messageBody, $messageCode, $messageArguments, $messageTitle);
+                break;
+            default:
+                $message = $this->objectManager->get(Message::class, $messageBody, $messageCode, $messageArguments, $messageTitle);
+                break;
+        }
+
+        $flashMessage = $this->objectManager->get(FlashMessage::class,
+            $message->render(), $message->getTitle(), $severity, true
+        );
+
+        $this->finisherContext->getControllerContext()->getFlashMessageQueue()->addMessage($flashMessage);
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Finishers/RedirectFinisher.php b/typo3/sysext/form/Classes/Domain/Finishers/RedirectFinisher.php
new file mode 100644
index 0000000000000000000000000000000000000000..0d20268f11b5b1890172b9d1c319c5f4bb17f0d8
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Finishers/RedirectFinisher.php
@@ -0,0 +1,151 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Finishers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
+use TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException;
+use TYPO3\CMS\Extbase\Mvc\Web\Request;
+use TYPO3\CMS\Extbase\Mvc\Web\Response;
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
+
+/**
+ * This finisher redirects to another Controller.
+ *
+ * Scope: frontend
+ */
+class RedirectFinisher extends AbstractFinisher
+{
+
+    /**
+     * @var array
+     */
+    protected $defaultOptions = [
+        'pageUid' => 1,
+        'additionalParameters' => '',
+        'delay' => 0,
+        'statusCode' => 303,
+    ];
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Mvc\Web\Request
+     */
+    protected $request;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Mvc\Web\Response
+     */
+    protected $response;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder
+     */
+    protected $uriBuilder;
+
+    /**
+     * Executes this finisher
+     * @see AbstractFinisher::execute()
+     *
+     * @return void
+     */
+    protected function executeInternal()
+    {
+        $formRuntime = $this->finisherContext->getFormRuntime();
+        $this->request = $formRuntime->getRequest();
+        $this->response = $formRuntime->getResponse();
+        $this->uriBuilder = $this->objectManager->get(UriBuilder::class);
+        $this->uriBuilder->setRequest($this->request);
+
+        $pageUid = (int)str_replace('pages_', '', $this->parseOption('pageUid'));
+        $additionalParameters = $this->parseOption('additionalParameters');
+        $additionalParameters = '&' . ltrim($additionalParameters, '&');
+        $delay = (int)$this->parseOption('delay');
+        $statusCode = (int)$this->parseOption('statusCode');
+
+        $this->finisherContext->cancel();
+        $this->redirect($pageUid, $additionalParameters, $delay, $statusCode);
+    }
+
+    /**
+     * Redirects the request to another page.
+     *
+     * Redirect will be sent to the client which then performs another request to the new URI.
+     *
+     * NOTE: This method only supports web requests and will thrown an exception
+     * if used with other request types.
+     *
+     * @param int $pageUid Target page uid. If NULL, the current page uid is used
+     * @param string $additionalParameters
+     * @param int $delay (optional) The delay in seconds. Default is no delay.
+     * @param int $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other
+     * @return void
+     * @throws UnsupportedRequestTypeException If the request is not a web request
+     * @see forward()
+     */
+    protected function redirect(int $pageUid = 1, string $additionalParameters = '', int $delay = 0, int $statusCode = 303)
+    {
+        if (!$this->request instanceof Request) {
+            throw new UnsupportedRequestTypeException('redirect() only supports web requests.', 1471776457);
+        }
+
+        $typolinkConfiguration = [
+            'parameter' => $pageUid,
+            'additionalParams' => $additionalParameters,
+        ];
+        $redirectUri = $this->getTypoScriptFrontendController()->cObj->typoLink_URL($typolinkConfiguration);
+        $this->redirectToUri($redirectUri, $delay, $statusCode);
+    }
+
+    /**
+     * Redirects the web request to another uri.
+     *
+     * NOTE: This method only supports web requests and will thrown an exception if used with other request types.
+     *
+     * @param string $uri A string representation of a URI
+     * @param int $delay (optional) The delay in seconds. Default is no delay.
+     * @param int $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other
+     * @throws UnsupportedRequestTypeException If the request is not a web request
+     * @throws StopActionException
+     */
+    protected function redirectToUri(string $uri, int $delay = 0, int $statusCode = 303)
+    {
+        if (!$this->request instanceof Request) {
+            throw new UnsupportedRequestTypeException('redirect() only supports web requests.', 1471776458);
+        }
+
+        $uri = $this->addBaseUriIfNecessary($uri);
+        $escapedUri = htmlentities($uri, ENT_QUOTES, 'utf-8');
+
+        $this->response->setContent('<html><head><meta http-equiv="refresh" content="' . (int)$delay . ';url=' . $escapedUri . '"/></head></html>');
+        if ($this->response instanceof \TYPO3\CMS\Extbase\Mvc\Web\Response) {
+            $this->response->setStatus($statusCode);
+            $this->response->setHeader('Location', (string)$uri);
+        }
+        echo $this->response->shutdown();
+        throw new StopActionException('redirectToUri', 1477070964);
+    }
+
+    /**
+     * Adds the base uri if not already in place.
+     *
+     * @param string $uri The URI
+     * @return string
+     */
+    protected function addBaseUriIfNecessary(string $uri): string
+    {
+        return GeneralUtility::locationHeaderUrl((string)$uri);
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Finishers/SaveToDatabaseFinisher.php b/typo3/sysext/form/Classes/Domain/Finishers/SaveToDatabaseFinisher.php
new file mode 100644
index 0000000000000000000000000000000000000000..bb7eb27a7f16bfeb3d93b26d9edc03fba5621ba8
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Finishers/SaveToDatabaseFinisher.php
@@ -0,0 +1,100 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Finishers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Domain\Model\FileReference;
+use TYPO3\CMS\Form\Domain\Finishers\Exception\FinisherException;
+use TYPO3\CMS\Form\Domain\Model\FormElements\FormElementInterface;
+
+/**
+ * This finisher saves the data from a submitted form into
+ * a database table.
+ *
+ * Scope: frontend
+ */
+class SaveToDatabaseFinisher extends AbstractFinisher
+{
+
+    /**
+     * @var array
+     */
+    protected $defaultOptions = [
+        'table' => null,
+        'elements' => [],
+    ];
+
+    /**
+     * Executes this finisher
+     * @see AbstractFinisher::execute()
+     *
+     * @return void
+     * @throws FinisherException
+     */
+    protected function executeInternal()
+    {
+        $table = $this->parseOption('table');
+        $elementsConfiguration = $this->parseOption('elements');
+
+        $databaseConnection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($table);
+        $schemaManager = $databaseConnection->getSchemaManager();
+
+        if ($schemaManager->tablesExist([$table]) === false) {
+            throw new FinisherException('The table "' . $table . '" does not exist.', 1476362091);
+        }
+
+        $databaseColumns = $schemaManager->listTableColumns($table);
+        foreach ($elementsConfiguration as $elementIdentifier => $elementConfiguration) {
+            if (!array_key_exists($elementConfiguration['mapOnDatabaseColumn'], $databaseColumns)) {
+                throw new FinisherException('The column "' . $elementConfiguration['mapOnDatabaseColumn'] . '" does not exist in table "' . $table . '".', 1476362572);
+            }
+        }
+
+        $formRuntime = $this->finisherContext->getFormRuntime();
+
+        $insertData = [];
+        foreach ($this->finisherContext->getFormValues() as $elementIdentifier => $elementValue) {
+            $element = $formRuntime->getFormDefinition()->getElementByIdentifier($elementIdentifier);
+            if (
+                !$element instanceof FormElementInterface
+                || !isset($elementsConfiguration[$elementIdentifier])
+                || !isset($elementsConfiguration[$elementIdentifier]['mapOnDatabaseColumn'])
+            ) {
+                continue;
+            }
+
+            if ($elementValue instanceof FileReference) {
+                if (isset($elementsConfiguration[$elementIdentifier]['saveFileIdentifierInsteadOfUid'])) {
+                    $saveFileIdentifierInsteadOfUid = (bool)$elementsConfiguration[$elementIdentifier]['saveFileIdentifierInsteadOfUid'];
+                } else {
+                    $saveFileIdentifierInsteadOfUid = false;
+                }
+
+                if ($saveFileIdentifierInsteadOfUid) {
+                    $elementValue = $elementValue->getOriginalResource()->getCombinedIdentifier();
+                } else {
+                    $elementValue = $elementValue->getOriginalResource()->getProperty('uid_local');
+                }
+            }
+            $insertData[$elementsConfiguration[$elementIdentifier]['mapOnDatabaseColumn']] = $elementValue;
+        }
+
+        if (!empty($insertData)) {
+            $databaseConnection->insert($table, $insertData);
+        }
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Configuration.php b/typo3/sysext/form/Classes/Domain/Model/Configuration.php
deleted file mode 100644
index f923ab8e35fca8bb51ee4544c3c28d442f954016..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Configuration.php
+++ /dev/null
@@ -1,174 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * The Configuration model is a high-level API
- * for the underlying TypoScript configuration.
- */
-class Configuration
-{
-    /**
-     * @var string
-     */
-    const DISABLE_CONTENT_ELEMENT_RENDERING = 'disableContentElement';
-
-    /**
-     * @var string
-     */
-    const DEFAULT_THEME_NAME = 'Default';
-
-    /**
-     * @return Configuration
-     */
-    public static function create()
-    {
-        return \TYPO3\CMS\Form\Utility\FormUtility::getObjectManager()->get(self::class);
-    }
-
-    /**
-     * @var array
-     */
-    protected $typoScript = [];
-
-    /**
-     * @var bool
-     */
-    protected $contentElementRendering = false;
-
-    /**
-     * @var string
-     */
-    protected $prefix = 'form';
-
-    /**
-     * @var string
-     */
-    protected $themeName = '';
-
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository
-     */
-    protected $typoScriptRepository;
-
-    /**
-     * @param \TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository $typoScriptRepository
-     * @return void
-     */
-    public function injectTypoScriptRepository(\TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository $typoScriptRepository)
-    {
-        $this->typoScriptRepository = $typoScriptRepository;
-    }
-
-    /**
-     * @return array
-     */
-    public function getTypoScript()
-    {
-        return $this->typoScript;
-    }
-
-    /**
-     * @param array $typoScript
-     * @return Configuration
-     */
-    public function setTypoScript(array $typoScript)
-    {
-        $this->typoScript = $typoScript;
-        $this->update();
-        return $this;
-    }
-
-    public function getContentElementRendering()
-    {
-        return $this->contentElementRendering;
-    }
-
-    /**
-     * @param $contentElementRendering
-     * @return Configuration
-     */
-    public function setContentElementRendering($contentElementRendering)
-    {
-        $this->contentElementRendering = (bool)$contentElementRendering;
-        return $this;
-    }
-
-    /**
-     * @return string
-     */
-    public function getPrefix()
-    {
-        return $this->prefix;
-    }
-
-    /**
-     * @param string $prefix
-     * @return Configuration
-     */
-    public function setPrefix($prefix)
-    {
-        $this->prefix = (string)$prefix;
-        return $this;
-    }
-
-    /**
-     * @return string
-     */
-    public function getThemeName()
-    {
-        return $this->themeName;
-    }
-
-    /**
-     * @param string $themeName
-     * @return Configuration
-     */
-    public function setThemeName($themeName = '')
-    {
-        if ($themeName === '') {
-            $themeName = static::DEFAULT_THEME_NAME;
-        }
-        $this->themeName = $themeName;
-        return $this;
-    }
-
-    /**
-     * Updates the local properties - called after
-     * new TypoScript has been assigned in this object.
-     */
-    protected function update()
-    {
-        // Determine content rendering mode. If activated, cObject and stdWrap can be
-        // used to execute various processes that must not be allowed on TypoScript
-        // that has been created by non-privileged backend users (= insecure TypoScript)
-        $this->setContentElementRendering(
-            empty($this->typoScript[static::DISABLE_CONTENT_ELEMENT_RENDERING])
-        );
-        // Determine the HTML form element prefix to distinguish
-        // different form components on the same page in the frontend
-        if (!empty($this->typoScript['prefix'])) {
-            $this->setPrefix($this->typoScript['prefix']);
-        }
-        // Set the theme name
-        if (!empty($this->typoScript['themeName'])) {
-            $this->setThemeName($this->typoScript['themeName']);
-        } elseif (!empty($this->typoScriptRepository->getModelConfigurationByScope('FORM', 'themeName'))) {
-            $this->setThemeName($this->typoScriptRepository->getModelConfigurationByScope('FORM', 'themeName'));
-        } else {
-            $this->setThemeName(static::DEFAULT_THEME_NAME);
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Content.php b/typo3/sysext/form/Classes/Domain/Model/Content.php
deleted file mode 100644
index c171aa4664f30ae82d5db58cb505390151e76909..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Content.php
+++ /dev/null
@@ -1,133 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Content domain model
- */
-class Content
-{
-    /**
-     * The uid
-     *
-     * @var int
-     */
-    protected $uid = 0;
-
-    /**
-     * The page id
-     *
-     * @var int
-     */
-    protected $pageId = 0;
-
-    /**
-     * The configuration Typoscript
-     *
-     * @var array
-     */
-    protected $typoscript = [];
-
-    /**
-     * The plain bodytext
-     *
-     * @var string
-     */
-    protected $bodytext = '';
-
-    /**
-     * Sets the uid
-     *
-     * @param int $uid The uid
-     * @return void
-     */
-    public function setUid($uid)
-    {
-        $this->uid = (int)$uid;
-    }
-
-    /**
-     * Returns the uid
-     *
-     * @return int The uid
-     */
-    public function getUid()
-    {
-        return $this->uid;
-    }
-
-    /**
-     * Sets the page id
-     *
-     * @param int $pageId The page id
-     * @return void
-     */
-    public function setPageId($pageId)
-    {
-        $this->pageId = (int)$pageId;
-    }
-
-    /**
-     * Returns the page id
-     *
-     * @return int The page id
-     */
-    public function getPageId()
-    {
-        return $this->pageId;
-    }
-
-    /**
-     * Sets the Typoscript configuration
-     *
-     * @param array $typoscript The Typoscript configuration
-     * @return void
-     */
-    public function setTyposcript(array $typoscript)
-    {
-        $this->typoscript = (array)$typoscript;
-    }
-
-    /**
-     * Returns the Typoscript configuration
-     *
-     * @return array The Typoscript configuration
-     */
-    public function getTyposcript()
-    {
-        return $this->typoscript;
-    }
-
-    /**
-     * Sets the bodytext
-     *
-     * @param string $bodytext The bodytext
-     * @return void
-     */
-    public function setBodytext($bodytext = '')
-    {
-        $this->bodytext = $bodytext;
-    }
-
-    /**
-     * Returns the bodytext
-     *
-     * @return string The bodytext
-     */
-    public function getBodytext()
-    {
-        return $this->bodytext;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Element.php b/typo3/sysext/form/Classes/Domain/Model/Element.php
deleted file mode 100644
index 6f2941ed7430e26db67204f89aadd80a9541186f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Element.php
+++ /dev/null
@@ -1,485 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
-use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
-
-/**
- * The Element Domain Model represents the high-level
- * view on the user submitted data using a nested hierarchy.
- */
-class Element extends AbstractEntity
-{
-    /**
-     * This array holds all the additional arguments to use it in the template
-     *
-     * @var array
-     */
-    protected $additionalArguments;
-
-    /**
-     * child elements
-     *
-     * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Form\Domain\Model\Element>
-     */
-    protected $childElements;
-
-    /**
-     * A global counter over all elements
-     *
-     * @var int
-     */
-    protected $elementCounter;
-
-    /**
-     * The element type (e.g BUTTON)
-     *
-     * @var string
-     */
-    protected $elementType;
-
-    /**
-     * The validation error messages
-     *
-     * @var array
-     */
-    protected $validationErrorMessages;
-
-    /**
-     * This array holds all the element html attributes with their values
-     *
-     * @var array
-     */
-    protected $htmlAttributes;
-
-    /**
-     * The id attribute
-     *
-     * @var string
-     */
-    protected $id;
-
-    /**
-     * The mandatory validation messages
-     *
-     * @var array
-     */
-    protected $mandatoryValidationMessages;
-
-    /**
-     * The name attribute
-     *
-     * @var string
-     */
-    protected $name;
-
-    /**
-     * parent element
-     *
-     * @var \TYPO3\CMS\Form\Domain\Model\Element
-     */
-    protected $parentElement;
-
-    /**
-     * The fluid partial for the element
-     *
-     * @var string
-     */
-    protected $partialPath;
-
-    /**
-     * TRUE if the element should be displayed
-     *
-     * @var bool
-     */
-    protected $showElement;
-
-    /**
-     * The theme name
-     *
-     * @var string
-     */
-    protected $themeName;
-
-    /**
-     * Creates an instance.
-     */
-    public function __construct()
-    {
-        $this->initStorageObjects();
-    }
-
-    /**
-     * Initializes all ObjectStorage properties.
-     *
-     * @return void
-     */
-    protected function initStorageObjects()
-    {
-        $this->childElements = new ObjectStorage();
-    }
-
-    /**
-     * Return a array with all the additional arguments to use it in the template
-     *
-     * @return array
-     */
-    public function getAdditionalArguments()
-    {
-        return $this->additionalArguments;
-    }
-
-    /**
-     * Sets a array with all the additional arguments to use it in the template
-     *
-     * @param array $additionalArguments
-     * @return void
-     */
-    public function setAdditionalArguments($additionalArguments = [])
-    {
-        $this->additionalArguments = $additionalArguments;
-    }
-
-    /**
-     * Get a single attribute value
-     *
-     * @param string $key
-     * @return array
-     */
-    public function getAdditionalArgument($key = '')
-    {
-        return $this->additionalArguments[$key];
-    }
-
-    /**
-     * Set a single attribute and value
-     *
-     * @param string $key
-     * @param mixed $value
-     * @return array
-     */
-    public function setAdditionalArgument($key = '', $value = null)
-    {
-        $this->additionalArguments[$key] = $value;
-    }
-
-    /**
-     * Adds a child element
-     *
-     * @param \TYPO3\CMS\Form\Domain\Model\Element $element
-     * @return void
-     */
-    public function addChildElement(Element $element)
-    {
-        $this->childElements->attach($element);
-    }
-
-    /**
-     * Returns the child elements
-     *
-     * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Form\Domain\Model\Element> $element
-     */
-    public function getChildElements()
-    {
-        return $this->childElements;
-    }
-
-    /**
-     * Sets the child elements
-     *
-     * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Form\Domain\Model\Element> $childElements
-     * @return void
-     */
-    public function setChildElements(ObjectStorage $childElements)
-    {
-        $this->childElements = $childElements;
-    }
-
-    /**
-     * Returns the element counter
-     *
-     * @return int
-     */
-    public function getElementCounter()
-    {
-        return $this->elementCounter;
-    }
-
-    /**
-     * Sets the element counter
-     *
-     * @param int $elementCounter
-     * @return void
-     */
-    public function setElementCounter($elementCounter = 0)
-    {
-        $this->elementCounter = $elementCounter;
-    }
-
-    /**
-     * Returns the element type
-     *
-     * @return string
-     */
-    public function getElementType()
-    {
-        return $this->elementType;
-    }
-
-    /**
-     * Returns the element type in lower case
-     *
-     * @return string
-     */
-    public function getElementTypeLowerCase()
-    {
-        return strtolower($this->elementType);
-    }
-
-    /**
-     * Sets the parent element
-     *
-     * @param string $elementType
-     * @return void
-     */
-    public function setElementType($elementType)
-    {
-        $this->elementType = (string)$elementType;
-    }
-
-    /**
-     * Returns the validation error messages
-     *
-     * @return array
-     */
-    public function getValidationErrorMessages()
-    {
-        return $this->validationErrorMessages;
-    }
-
-    /**
-     * Sets the validation error messages
-     *
-     * @param array $validationErrorMessages
-     * @return void
-     */
-    public function setValidationErrorMessages(array $validationErrorMessages)
-    {
-        $this->validationErrorMessages = $validationErrorMessages;
-    }
-
-    /**
-     * Returns the element html attributes and values
-     *
-     * @return array
-     */
-    public function getHtmlAttributes()
-    {
-        return $this->htmlAttributes;
-    }
-
-    /**
-     * Sets the element html attributes and values
-     *
-     * @param array $htmlAttributes
-     * @return void
-     */
-    public function setHtmlAttributes($htmlAttributes = [])
-    {
-        $this->htmlAttributes = $htmlAttributes;
-    }
-
-    /**
-     * Remove a single html attribute
-     *
-     * @param string $key
-     * @return void
-     */
-    public function removeHtmlAttribute($key = '')
-    {
-        unset($this->htmlAttributes[$key]);
-    }
-
-    /**
-     * Get a single html attribute value
-     *
-     * @param string $key
-     * @return array
-     */
-    public function getHtmlAttribute($key = '')
-    {
-        return $this->htmlAttributes[$key];
-    }
-
-    /**
-     * Set a single html attribute and value
-     *
-     * @param string $key
-     * @param mixed $value
-     * @return array
-     */
-    public function setHtmlAttribute($key = '', $value = null)
-    {
-        $this->htmlAttributes[$key] = $value;
-    }
-
-    /**
-     * Returns the id attribute
-     *
-     * @return string
-     */
-    public function getId()
-    {
-        return $this->id;
-    }
-
-    /**
-     * Sets the id attribute
-     *
-     * @param string $id
-     * @return void
-     */
-    public function setId($id)
-    {
-        $this->id = (string)$id;
-    }
-
-    /**
-     * Returns the mandatory validation messages
-     *
-     * @return array
-     */
-    public function getMandatoryValidationMessages()
-    {
-        return $this->mandatoryValidationMessages;
-    }
-
-    /**
-     * Sets the mandatory validation messages
-     *
-     * @param array $mandatoryValidationMessages
-     * @return void
-     */
-    public function setMandatoryValidationMessages(array $mandatoryValidationMessages)
-    {
-        $this->mandatoryValidationMessages = $mandatoryValidationMessages;
-    }
-
-    /**
-     * Returns the name attribute
-     *
-     * @return string
-     */
-    public function getName()
-    {
-        return $this->name;
-    }
-
-    /**
-     * Sets the name attribute
-     *
-     * @param string $name
-     * @return void
-     */
-    public function setName($name)
-    {
-        $this->name = (string)$name;
-    }
-
-    /**
-     * Returns the parent element
-     *
-     * @return Element
-     */
-    public function getParentElement()
-    {
-        return $this->parentElement;
-    }
-
-    /**
-     * Sets the parent element
-     *
-     * @param \TYPO3\CMS\Form\Domain\Model\Element
-     * @return void
-     */
-    public function setParentElement(Element $parentElement)
-    {
-        $this->parentElement = $parentElement;
-    }
-
-    /**
-     * Returns the fluid partial path for the element
-     *
-     * @return string
-     */
-    public function getPartialPath()
-    {
-        return $this->partialPath;
-    }
-
-    /**
-     * Sets the fluid partial path for the element
-     *
-     * @param string $partialPath
-     * @return void
-     */
-    public function setPartialPath($partialPath)
-    {
-        $this->partialPath = (string)$partialPath;
-    }
-
-    /**
-     * Returns TRUE if the element should be displayed
-     *
-     * @return bool
-     */
-    public function getShowElement()
-    {
-        return $this->showElement;
-    }
-
-    /**
-     * TRUE if the element should be displayed
-     *
-     * @param bool $showElement
-     * @return void
-     */
-    public function setShowElement($showElement = false)
-    {
-        $this->showElement = $showElement;
-    }
-
-    /**
-     * Set the theme name
-     *
-     * @param string
-     * @return $themeName
-     */
-    public function setThemeName($themeName = 'Default')
-    {
-        $this->themeName = $themeName;
-    }
-
-    /**
-     * Returns the theme name
-     *
-     * @return string
-     */
-    public function getThemeName()
-    {
-        return $this->themeName;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Exception.php b/typo3/sysext/form/Classes/Domain/Model/Exception.php
new file mode 100644
index 0000000000000000000000000000000000000000..5704857b747801855500ece2616df12dd1ba60fb
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/Exception.php
@@ -0,0 +1,27 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Exception as DomainException;
+
+/**
+ * A generic Form model Exception
+ *
+ * @api
+ */
+class Exception extends DomainException
+{
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Exception/DuplicateFormElementException.php b/typo3/sysext/form/Classes/Domain/Model/Exception/DuplicateFormElementException.php
new file mode 100644
index 0000000000000000000000000000000000000000..83f718abf26e3e39a26bc06042e6cb8103d1c66d
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/Exception/DuplicateFormElementException.php
@@ -0,0 +1,28 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Model\Exception;
+
+/**
+ * This exception is thrown if two Form Elements with the same Identifier are added
+ * to a form.
+ *
+ * @api
+ */
+class DuplicateFormElementException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Exception/FinisherPresetNotFoundException.php b/typo3/sysext/form/Classes/Domain/Model/Exception/FinisherPresetNotFoundException.php
new file mode 100644
index 0000000000000000000000000000000000000000..5200d0e0cb81d52dfec1e3eb61c27c632740d5d3
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/Exception/FinisherPresetNotFoundException.php
@@ -0,0 +1,28 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Model\Exception;
+
+/**
+ * This exception is thrown if a Finisher Preset was not found,
+ * or if the implementationClassName was not set.
+ *
+ * @api
+ */
+class FinisherPresetNotFoundException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Exception/FormDefinitionConsistencyException.php b/typo3/sysext/form/Classes/Domain/Model/Exception/FormDefinitionConsistencyException.php
new file mode 100644
index 0000000000000000000000000000000000000000..d04d41cd272be89901c76b6ab488f37bf8d022ed
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/Exception/FormDefinitionConsistencyException.php
@@ -0,0 +1,28 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Model\Exception;
+
+/**
+ * This exception is thrown if the form definition would get an inconsistent state, like
+ * adding a page to two different forms
+ *
+ * @api
+ */
+class FormDefinitionConsistencyException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Exception/ValidatorPresetNotFoundException.php b/typo3/sysext/form/Classes/Domain/Model/Exception/ValidatorPresetNotFoundException.php
new file mode 100644
index 0000000000000000000000000000000000000000..cfacf8e2e38313d61cdf00fc8397babf1d470667
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/Exception/ValidatorPresetNotFoundException.php
@@ -0,0 +1,28 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Model\Exception;
+
+/**
+ * This exception is thrown if a Validator Preset was not found,
+ * or if the implementationClassName was not set.
+ *
+ * @api
+ */
+class ValidatorPresetNotFoundException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/FormDefinition.php b/typo3/sysext/form/Classes/Domain/Model/FormDefinition.php
new file mode 100644
index 0000000000000000000000000000000000000000..d619d70c47e65e0e22cc517597cd6b9af79d72e7
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/FormDefinition.php
@@ -0,0 +1,695 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\ArrayUtility as CoreArrayUtility;
+use TYPO3\CMS\Extbase\Mvc\Web\Request;
+use TYPO3\CMS\Extbase\Mvc\Web\Response;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
+use TYPO3\CMS\Extbase\Utility\ArrayUtility;
+use TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException;
+use TYPO3\CMS\Form\Domain\Exception\TypeDefinitionNotFoundException;
+use TYPO3\CMS\Form\Domain\Finishers\FinisherInterface;
+use TYPO3\CMS\Form\Domain\Model\Exception\DuplicateFormElementException;
+use TYPO3\CMS\Form\Domain\Model\Exception\FinisherPresetNotFoundException;
+use TYPO3\CMS\Form\Domain\Model\Exception\FormDefinitionConsistencyException;
+use TYPO3\CMS\Form\Domain\Model\FormElements\FormElementInterface;
+use TYPO3\CMS\Form\Domain\Model\FormElements\Page;
+use TYPO3\CMS\Form\Domain\Model\Renderable\AbstractCompositeRenderable;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+use TYPO3\CMS\Form\Exception as FormException;
+use TYPO3\CMS\Form\Mvc\ProcessingRule;
+use TYPO3\CMS\Form\Utility\ArrayUtility as FormArrayUtility;
+
+/**
+ * This class encapsulates a complete *Form Definition*, with all of its pages,
+ * form elements, validation rules which apply and finishers which should be
+ * executed when the form is completely filled in.
+ *
+ * It is *not modified* when the form executes.
+ *
+ * The Anatomy Of A Form
+ * =====================
+ *
+ * A FormDefinition consists of multiple *Page* ({@link Page}) objects. When a
+ * form is displayed to the user, only one *Page* is visible at any given time,
+ * and there is a navigation to go back and forth between the pages.
+ *
+ * A *Page* consists of multiple *FormElements* ({@link FormElementInterface}, {@link AbstractFormElement}),
+ * which represent the input fields, textareas, checkboxes shown inside the page.
+ *
+ * *FormDefinition*, *Page* and *FormElement* have *identifier* properties, which
+ * must be unique for each given type (i.e. it is allowed that the FormDefinition and
+ * a FormElement have the *same* identifier, but two FormElements are not allowed to
+ * have the same identifier.
+ *
+ * Simple Example
+ * --------------
+ *
+ * Generally, you can create a FormDefinition manually by just calling the API
+ * methods on it, or you use a *Form Definition Factory* to build the form from
+ * another representation format such as YAML.
+ *
+ * /---code php
+ * $formDefinition = $this->objectManager->get(FormDefinition::class, 'myForm');
+ *
+ * $page1 = $this->objectManager->get(Page::class, 'page1');
+ * $formDefinition->addPage($page);
+ *
+ * $element1 = $this->objectManager->get(GenericFormElement::class, 'title', 'Textfield'); # the second argument is the type of the form element
+ * $page1->addElement($element1);
+ * \---
+ *
+ * Creating a Form, Using Abstract Form Element Types
+ * =====================================================
+ *
+ * While you can use the {@link FormDefinition::addPage} or {@link Page::addElement}
+ * methods and create the Page and FormElement objects manually, it is often better
+ * to use the corresponding create* methods ({@link FormDefinition::createPage}
+ * and {@link Page::createElement}), as you pass them an abstract *Form Element Type*
+ * such as *Text* or *Page*, and the system **automatically
+ * resolves the implementation class name and sets default values**.
+ *
+ * So the simple example from above should be rewritten as follows:
+ *
+ * /---code php
+ * $prototypeConfiguration = []; // We'll talk about this later
+ *
+ * $formDefinition = $this->objectManager->get(FormDefinition::class, 'myForm', $prototypeConfiguration);
+ * $page1 = $formDefinition->createPage('page1');
+ * $element1 = $page1->addElement('title', 'Textfield');
+ * \---
+ *
+ * Now, you might wonder how the system knows that the element *Textfield*
+ * is implemented using a GenericFormElement: **This is configured in the $prototypeConfiguration**.
+ *
+ * To make the example from above actually work, we need to add some sensible
+ * values to *$prototypeConfiguration*:
+ *
+ * <pre>
+ * $prototypeConfiguration = [
+ *   'formElementsDefinition' => [
+ *     'Page' => [
+ *       'implementationClassName' => 'TYPO3\CMS\Form\Domain\Model\FormElements\Page'
+ *     ],
+ *     'Textfield' => [
+ *       'implementationClassName' => 'TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement'
+ *     ]
+ *   ]
+ * ]
+ * </pre>
+ *
+ * For each abstract *Form Element Type* we add some configuration; in the above
+ * case only the *implementation class name*. Still, it is possible to set defaults
+ * for *all* configuration options of such an element, as the following example
+ * shows:
+ *
+ * <pre>
+ * $prototypeConfiguration = [
+ *   'formElementsDefinition' => [
+ *     'Page' => [
+ *       'implementationClassName' => 'TYPO3\CMS\Form\Domain\Model\FormElements\Page',
+ *       'label' => 'this is the label of the page if nothing is specified'
+ *     ],
+ *     'Textfield' => [
+ *       'implementationClassName' => 'TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement',
+ *       'label' = >'Default Label',
+ *       'defaultValue' => 'Default form element value',
+ *       'properties' => [
+ *         'placeholder' => 'Text which is shown if element is empty'
+ *       ]
+ *     ]
+ *   ]
+ * ]
+ * </pre>
+ *
+ * Using Preconfigured $prototypeConfiguration
+ * ---------------------------------
+ *
+ * Often, it is not really useful to manually create the $prototypeConfiguration array.
+ *
+ * Most of it comes pre-configured inside the extensions's yaml settings,
+ * and the {@link \TYPO3\CMS\Form\Domain\Configuration\ConfigurationService} contains helper methods
+ * which return the ready-to-use *$prototypeConfiguration*.
+ *
+ * Property Mapping and Validation Rules
+ * =====================================
+ *
+ * Besides Pages and FormElements, the FormDefinition can contain information
+ * about the *format of the data* which is inputted into the form. This generally means:
+ *
+ * - expected Data Types
+ * - Property Mapping Configuration to be used
+ * - Validation Rules which should apply
+ *
+ * Background Info
+ * ---------------
+ * You might wonder why Data Types and Validation Rules are *not attached
+ * to each FormElement itself*.
+ *
+ * If the form should create a *hierarchical output structure* such as a multi-
+ * dimensional array or a PHP object, your expected data structure might look as follows:
+ * <pre>
+ * - person
+ * -- firstName
+ * -- lastName
+ * -- address
+ * --- street
+ * --- city
+ * </pre>
+ *
+ * Now, let's imagine you want to edit *person.address.street* and *person.address.city*,
+ * but want to validate that the *combination* of *street* and *city* is valid
+ * according to some address database.
+ *
+ * In this case, the form elements would be configured to fill *street* and *city*,
+ * but the *validator* needs to be attached to the *compound object* *address*,
+ * as both parts need to be validated together.
+ *
+ * Connecting FormElements to the output data structure
+ * ====================================================
+ *
+ * The *identifier* of the *FormElement* is most important, as it determines
+ * where in the output structure the value which is entered by the user is placed,
+ * and thus also determines which validation rules need to apply.
+ *
+ * Using the above example, if you want to create a FormElement for the *street*,
+ * you should use the identifier *person.address.street*.
+ *
+ * Rendering a FormDefinition
+ * ==========================
+ *
+ * In order to trigger *rendering* on a FormDefinition,
+ * the current {@link \TYPO3\CMS\Extbase\Mvc\Web\Request} needs to be bound to the FormDefinition,
+ * resulting in a {@link \TYPO3\CMS\Form\Domain\Runtime\FormRuntime} object which contains the *Runtime State* of the form
+ * (such as the currently inserted values).
+ *
+ * /---code php
+ * # $currentRequest and $currentResponse need to be available, f.e. inside a controller you would
+ * # use $this->request and $this->response; inside a ViewHelper you would use $this->controllerContext->getRequest()
+ * # and $this->controllerContext->getResponse()
+ * $form = $formDefinition->bind($currentRequest, $currentResponse);
+ *
+ * # now, you can use the $form object to get information about the currently
+ * # entered values into the form, etc.
+ * \---
+ *
+ * Refer to the {@link \TYPO3\CMS\Form\Domain\Runtime\FormRuntime} API doc for further information.
+ *
+ * Scope: frontend
+ * **This class is NOT meant to be sub classed by developers.**
+ */
+class FormDefinition extends AbstractCompositeRenderable
+{
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * The finishers for this form
+     *
+     * @var \TYPO3\CMS\Form\Domain\Finishers\FinisherInterface[]
+     */
+    protected $finishers = [];
+
+    /**
+     * Property Mapping Rules, indexed by element identifier
+     *
+     * @var \TYPO3\CMS\Form\Mvc\ProcessingRule[]
+     */
+    protected $processingRules = [];
+
+    /**
+     * Contains all elements of the form, indexed by identifier.
+     * Is used as internal cache as we need this really often.
+     *
+     * @var \TYPO3\CMS\Form\Domain\Model\FormElements\FormElementInterface[]
+     */
+    protected $elementsByIdentifier = [];
+
+    /**
+     * Form element default values in the format ['elementIdentifier' => 'default value']
+     *
+     * @var array
+     */
+    protected $elementDefaultValues = [];
+
+    /**
+     * @var array
+     */
+    protected $typeDefinitions;
+
+    /**
+     * @var array
+     */
+    protected $validatorsDefinition;
+
+    /**
+     * @var array
+     */
+    protected $finishersDefinition;
+
+    /**
+     * The persistence identifier of the form
+     *
+     * @var string
+     */
+    protected $persistenceIdentifier = null;
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
+     * @internal
+     */
+    public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
+    {
+        $this->objectManager = $objectManager;
+    }
+
+    /**
+     * Constructor. Creates a new FormDefinition with the given identifier.
+     *
+     * @param string $identifier The Form Definition's identifier, must be a non-empty string.
+     * @param array $prototypeConfiguration overrides form defaults of this definition
+     * @param string $type element type of this form
+     * @param string $persistenceIdentifier the persistence identifier of the form
+     * @throws IdentifierNotValidException if the identifier was not valid
+     * @api
+     */
+    public function __construct(
+        string $identifier,
+        array $prototypeConfiguration = [],
+        string $type = 'Form',
+        string $persistenceIdentifier = null
+    ) {
+        $this->typeDefinitions = isset($prototypeConfiguration['formElementsDefinition']) ? $prototypeConfiguration['formElementsDefinition'] : [];
+        $this->validatorsDefinition = isset($prototypeConfiguration['validatorsDefinition']) ? $prototypeConfiguration['validatorsDefinition'] : [];
+        $this->finishersDefinition = isset($prototypeConfiguration['finishersDefinition']) ? $prototypeConfiguration['finishersDefinition'] : [];
+
+        if (!is_string($identifier) || strlen($identifier) === 0) {
+            throw new IdentifierNotValidException('The given identifier was not a string or the string was empty.', 1477082503);
+        }
+
+        $this->identifier = $identifier;
+        $this->type = $type;
+        $this->persistenceIdentifier = $persistenceIdentifier;
+
+        if ($prototypeConfiguration !== []) {
+            $this->initializeFromFormDefaults();
+        }
+    }
+
+    /**
+     * Initialize the form defaults of the current type
+     *
+     * @return void
+     * @throws TypeDefinitionNotFoundException
+     * @internal
+     */
+    protected function initializeFromFormDefaults()
+    {
+        if (!isset($this->typeDefinitions[$this->type])) {
+            throw new TypeDefinitionNotFoundException(sprintf('Type "%s" not found. Probably some configuration is missing.', $this->type), 1474905835);
+        }
+        $typeDefinition = $this->typeDefinitions[$this->type];
+        $this->setOptions($typeDefinition);
+    }
+
+    /**
+     * Set multiple properties of this object at once.
+     * Every property which has a corresponding set* method can be set using
+     * the passed $options array.
+     *
+     * @param array $options
+     * @return void
+     * @internal
+     */
+    public function setOptions(array $options)
+    {
+        if (isset($options['rendererClassName'])) {
+            $this->setRendererClassName($options['rendererClassName']);
+        }
+        if (isset($options['renderingOptions'])) {
+            foreach ($options['renderingOptions'] as $key => $value) {
+                if (is_array($value)) {
+                    $currentValue = isset($this->getRenderingOptions()[$key]) ? $this->getRenderingOptions()[$key] : [];
+                    CoreArrayUtility::mergeRecursiveWithOverrule($currentValue, $value);
+                    $this->setRenderingOption($key, $currentValue);
+                } else {
+                    $this->setRenderingOption($key, $value);
+                }
+            }
+        }
+        if (isset($options['finishers'])) {
+            foreach ($options['finishers'] as $finisherConfiguration) {
+                $this->createFinisher($finisherConfiguration['identifier'], isset($finisherConfiguration['options']) ? $finisherConfiguration['options'] : []);
+            }
+        }
+
+        FormArrayUtility::assertAllArrayKeysAreValid($options, ['rendererClassName', 'renderingOptions', 'finishers', 'formEditor']);
+    }
+
+    /**
+     * Create a page with the given $identifier and attach this page to the form.
+     *
+     * - Create Page object based on the given $typeName
+     * - set defaults inside the Page object
+     * - attach Page object to this form
+     * - return the newly created Page object
+     *
+     * @param string $identifier Identifier of the new page
+     * @param string $typeName Type of the new page
+     * @return Page the newly created page
+     * @throws TypeDefinitionNotFoundException
+     * @api
+     */
+    public function createPage(string $identifier, string $typeName = 'Page'): Page
+    {
+        if (!isset($this->typeDefinitions[$typeName])) {
+            throw new TypeDefinitionNotFoundException(sprintf('Type "%s" not found. Probably some configuration is missing.', $typeName), 1474905953);
+        }
+
+        $typeDefinition = $this->typeDefinitions[$typeName];
+
+        if (!isset($typeDefinition['implementationClassName'])) {
+            throw new TypeDefinitionNotFoundException(sprintf('The "implementationClassName" was not set in type definition "%s".', $typeName), 1477083126);
+        }
+        $implementationClassName = $typeDefinition['implementationClassName'];
+        $page = $this->objectManager->get($implementationClassName, $identifier, $typeName);
+
+        if (isset($typeDefinition['label'])) {
+            $page->setLabel($typeDefinition['label']);
+        }
+
+        if (isset($typeDefinition['rendererClassName'])) {
+            $page->setRendererClassName($typeDefinition['rendererClassName']);
+        }
+
+        if (isset($typeDefinition['renderingOptions'])) {
+            foreach ($typeDefinition['renderingOptions'] as $key => $value) {
+                $page->setRenderingOption($key, $value);
+            }
+        }
+
+        FormArrayUtility::assertAllArrayKeysAreValid($typeDefinition, ['implementationClassName', 'label', 'rendererClassName', 'renderingOptions', 'formEditor']);
+
+        $this->addPage($page);
+        return $page;
+    }
+
+    /**
+     * Add a new page at the end of the form.
+     *
+     * Instead of this method, you should often use {@link createPage} instead.
+     *
+     * @param Page $page
+     * @return void
+     * @throws FormDefinitionConsistencyException if Page is already added to a FormDefinition
+     * @see createPage
+     * @api
+     */
+    public function addPage(Page $page)
+    {
+        $this->addRenderable($page);
+    }
+
+    /**
+     * Get the Form's pages
+     *
+     * @return array<Page> The Form's pages in the correct order
+     * @api
+     */
+    public function getPages(): array
+    {
+        return $this->renderables;
+    }
+
+    /**
+     * Check whether a page with the given $index exists
+     *
+     * @param int $index
+     * @return bool TRUE if a page with the given $index exists, otherwise FALSE
+     * @api
+     */
+    public function hasPageWithIndex(int $index): bool
+    {
+        return isset($this->renderables[$index]);
+    }
+
+    /**
+     * Get the page with the passed index. The first page has index zero.
+     *
+     * If page at $index does not exist, an exception is thrown. @see hasPageWithIndex()
+     *
+     * @param int $index
+     * @return Page the page, or NULL if none found.
+     * @throws FormException if the specified index does not exist
+     * @api
+     */
+    public function getPageByIndex(int $index)
+    {
+        if (!$this->hasPageWithIndex($index)) {
+            throw new FormException(sprintf('There is no page with an index of %d', $index), 1329233627);
+        }
+        return $this->renderables[$index];
+    }
+
+    /**
+     * Adds the specified finisher to this form
+     *
+     * @param FinisherInterface $finisher
+     * @return void
+     * @api
+     */
+    public function addFinisher(FinisherInterface $finisher)
+    {
+        $this->finishers[] = $finisher;
+    }
+
+    /**
+     * @param string $finisherIdentifier identifier of the finisher as registered in the current form (for example: "Redirect")
+     * @param array $options options for this finisher in the format ['option1' => 'value1', 'option2' => 'value2', ...]
+     * @return FinisherInterface
+     * @throws FinisherPresetNotFoundException
+     * @api
+     */
+    public function createFinisher(string $finisherIdentifier, array $options = []): FinisherInterface
+    {
+        if (isset($this->finishersDefinition[$finisherIdentifier]) && is_array($this->finishersDefinition[$finisherIdentifier]) && isset($this->finishersDefinition[$finisherIdentifier]['implementationClassName'])) {
+            $implementationClassName = $this->finishersDefinition[$finisherIdentifier]['implementationClassName'];
+            $defaultOptions = isset($this->finishersDefinition[$finisherIdentifier]['options']) ? $this->finishersDefinition[$finisherIdentifier]['options'] : [];
+            CoreArrayUtility::mergeRecursiveWithOverrule($defaultOptions, $options);
+
+            $finisher = $this->objectManager->get($implementationClassName);
+            $finisher->setOptions($defaultOptions);
+            $this->addFinisher($finisher);
+            return $finisher;
+        } else {
+            throw new FinisherPresetNotFoundException('The finisher preset identified by "' . $finisherIdentifier . '" could not be found, or the implementationClassName was not specified.', 1328709784);
+        }
+    }
+
+    /**
+     * Gets all finishers of this form
+     *
+     * @return \TYPO3\CMS\Form\Domain\Finishers\FinisherInterface[]
+     * @api
+     */
+    public function getFinishers(): array
+    {
+        return $this->finishers;
+    }
+
+    /**
+     * Add an element to the ElementsByIdentifier Cache.
+     *
+     * @param RenderableInterface $renderable
+     * @return void
+     * @throws DuplicateFormElementException
+     * @internal
+     */
+    public function registerRenderable(RenderableInterface $renderable)
+    {
+        if ($renderable instanceof FormElementInterface) {
+            if (isset($this->elementsByIdentifier[$renderable->getIdentifier()])) {
+                throw new DuplicateFormElementException(sprintf('A form element with identifier "%s" is already part of the form.', $renderable->getIdentifier()), 1325663761);
+            }
+            $this->elementsByIdentifier[$renderable->getIdentifier()] = $renderable;
+        }
+    }
+
+    /**
+     * Remove an element from the ElementsByIdentifier cache
+     *
+     * @param RenderableInterface $renderable
+     * @return void
+     * @internal
+     */
+    public function unregisterRenderable(RenderableInterface $renderable)
+    {
+        if ($renderable instanceof FormElementInterface) {
+            unset($this->elementsByIdentifier[$renderable->getIdentifier()]);
+        }
+    }
+
+    /**
+     * Get a Form Element by its identifier
+     *
+     * If identifier does not exist, returns NULL.
+     *
+     * @param string $elementIdentifier
+     * @return FormElementInterface The element with the given $elementIdentifier or NULL if none found
+     * @api
+     */
+    public function getElementByIdentifier(string $elementIdentifier)
+    {
+        return isset($this->elementsByIdentifier[$elementIdentifier]) ? $this->elementsByIdentifier[$elementIdentifier] : null;
+    }
+
+    /**
+     * Sets the default value of a form element
+     *
+     * @param string $elementIdentifier identifier of the form element. This supports property paths!
+     * @param mixed $defaultValue
+     * @return void
+     * @internal
+     */
+    public function addElementDefaultValue(string $elementIdentifier, $defaultValue)
+    {
+        $this->elementDefaultValues = ArrayUtility::setValueByPath($this->elementDefaultValues, $elementIdentifier, $defaultValue);
+    }
+
+    /**
+     * returns the default value of the specified form element
+     * or NULL if no default value was set
+     *
+     * @param string $elementIdentifier identifier of the form element. This supports property paths!
+     * @return mixed The elements default value
+     * @internal
+     */
+    public function getElementDefaultValueByIdentifier(string $elementIdentifier)
+    {
+        return ObjectAccess::getPropertyPath($this->elementDefaultValues, $elementIdentifier);
+    }
+
+    /**
+     * Move $pageToMove before $referencePage
+     *
+     * @param Page $pageToMove
+     * @param Page $referencePage
+     * @return void
+     * @api
+     */
+    public function movePageBefore(Page $pageToMove, Page $referencePage)
+    {
+        $this->moveRenderableBefore($pageToMove, $referencePage);
+    }
+
+    /**
+     * Move $pageToMove after $referencePage
+     *
+     * @param Page $pageToMove
+     * @param Page $referencePage
+     * @return void
+     * @api
+     */
+    public function movePageAfter(Page $pageToMove, Page $referencePage)
+    {
+        $this->moveRenderableAfter($pageToMove, $referencePage);
+    }
+
+    /**
+     * Remove $pageToRemove from form
+     *
+     * @param Page $pageToRemove
+     * @return void
+     * @api
+     */
+    public function removePage(Page $pageToRemove)
+    {
+        $this->removeRenderable($pageToRemove);
+    }
+
+    /**
+     * Bind the current request & response to this form instance, effectively creating
+     * a new "instance" of the Form.
+     *
+     * @param Request $request
+     * @param Response $response
+     * @return FormRuntime
+     * @api
+     */
+    public function bind(Request $request, Response $response): FormRuntime
+    {
+        return $this->objectManager->get(FormRuntime::class, $this, $request, $response);
+    }
+
+    /**
+     * @param string $propertyPath
+     * @return ProcessingRule
+     * @api
+     */
+    public function getProcessingRule(string $propertyPath): ProcessingRule
+    {
+        if (!isset($this->processingRules[$propertyPath])) {
+            $this->processingRules[$propertyPath] = $this->objectManager->get(ProcessingRule::class);
+        }
+        return $this->processingRules[$propertyPath];
+    }
+
+    /**
+     * Get all mapping rules
+     *
+     * @return \TYPO3\CMS\Form\Mvc\ProcessingRule[]
+     * @internal
+     */
+    public function getProcessingRules(): array
+    {
+        return $this->processingRules;
+    }
+
+    /**
+     * @return array
+     * @internal
+     */
+    public function getTypeDefinitions(): array
+    {
+        return $this->typeDefinitions;
+    }
+
+    /**
+     * @return array
+     * @internal
+     */
+    public function getValidatorsDefinition(): array
+    {
+        return $this->validatorsDefinition;
+    }
+
+    /**
+     * Get the persistence identifier of the form
+     *
+     * @return string
+     * @internal
+     */
+    public function getPersistenceIdentifier(): string
+    {
+        return $this->persistenceIdentifier;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/FormElements/AbstractFormElement.php b/typo3/sysext/form/Classes/Domain/Model/FormElements/AbstractFormElement.php
new file mode 100644
index 0000000000000000000000000000000000000000..f977a975ada5d3952f41a46fd2c58cf5b095b20f
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/FormElements/AbstractFormElement.php
@@ -0,0 +1,168 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\FormElements;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator;
+use TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException;
+use TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+
+/**
+ * A base form element, which is the starting point for creating custom (PHP-based)
+ * Form Elements.
+ *
+ * A *FormElement* is a part of a *Page*, which in turn is part of a FormDefinition.
+ * See {@link FormDefinition} for an in-depth explanation.
+ *
+ * Subclassing this class is a good starting-point for implementing custom PHP-based
+ * Form Elements.
+ *
+ * Most of the functionality and API is implemented in {@link \TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable}, so
+ * make sure to check out this class as well.
+ *
+ * Still, it is quite rare that you need to subclass this class; often
+ * you can just use the {@link \TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement} and replace some templates.
+ *
+ * Scope: frontend
+ * **This class is meant to be sub classed by developers.**
+ */
+abstract class AbstractFormElement extends AbstractRenderable implements FormElementInterface
+{
+
+    /**
+     * @var array
+     */
+    protected $properties = [];
+
+    /**
+     * Constructor. Needs this FormElement's identifier and the FormElement type
+     *
+     * @param string $identifier The FormElement's identifier
+     * @param string $type The Form Element Type
+     * @throws IdentifierNotValidException
+     * @api
+     */
+    public function __construct(string $identifier, string $type)
+    {
+        if (!is_string($identifier) || strlen($identifier) === 0) {
+            throw new IdentifierNotValidException('The given identifier was not a string or the string was empty.', 1477082502);
+        }
+        $this->identifier = $identifier;
+        $this->type = $type;
+    }
+
+    /**
+     * Override this method in your custom FormElements if needed
+     *
+     * @return void
+     * @api
+     */
+    public function initializeFormElement()
+    {
+    }
+
+    /**
+     * Get the global unique identifier of the element
+     *
+     * @return string
+     * @api
+     */
+    public function getUniqueIdentifier(): string
+    {
+        $formDefinition = $this->getRootForm();
+        $uniqueIdentifier = sprintf('%s-%s', $formDefinition->getIdentifier(), $this->identifier);
+        $uniqueIdentifier = preg_replace('/[^a-zA-Z0-9-_]/', '_', $uniqueIdentifier);
+        return lcfirst($uniqueIdentifier);
+    }
+
+    /**
+     * Get the default value of the element
+     *
+     * @return mixed
+     * @api
+     */
+    public function getDefaultValue()
+    {
+        $formDefinition = $this->getRootForm();
+        return $formDefinition->getElementDefaultValueByIdentifier($this->identifier);
+    }
+
+    /**
+     * Set the default value of the element
+     *
+     * @param mixed $defaultValue
+     * @return void
+     * @api
+     */
+    public function setDefaultValue($defaultValue)
+    {
+        $formDefinition = $this->getRootForm();
+        $formDefinition->addElementDefaultValue($this->identifier, $defaultValue);
+    }
+
+    /**
+     * Check if the element is required
+     *
+     * @return bool
+     * @api
+     */
+    public function isRequired(): bool
+    {
+        foreach ($this->getValidators() as $validator) {
+            if ($validator instanceof NotEmptyValidator) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Set a property of the element
+     *
+     * @param string $key
+     * @param mixed $value
+     * @return void
+     * @api
+     */
+    public function setProperty(string $key, $value)
+    {
+        $this->properties[$key] = $value;
+    }
+
+    /**
+     * Get all properties
+     *
+     * @return array
+     * @api
+     */
+    public function getProperties(): array
+    {
+        return $this->properties;
+    }
+
+    /**
+     * Override this method in your custom FormElements if needed
+     *
+     * @param FormRuntime $formRuntime
+     * @param mixed $elementValue
+     * @param array $requestArguments submitted raw request values
+     * @return void
+     * @api
+     */
+    public function onSubmit(FormRuntime $formRuntime, &$elementValue, array $requestArguments = [])
+    {
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/FormElements/AbstractSection.php b/typo3/sysext/form/Classes/Domain/Model/FormElements/AbstractSection.php
new file mode 100644
index 0000000000000000000000000000000000000000..2754c6d1f7153fc94d95d4b5caaef61dc84ceefe
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/FormElements/AbstractSection.php
@@ -0,0 +1,199 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\FormElements;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException;
+use TYPO3\CMS\Form\Domain\Exception\TypeDefinitionNotFoundException;
+use TYPO3\CMS\Form\Domain\Exception\TypeDefinitionNotValidException;
+use TYPO3\CMS\Form\Domain\Model\Exception\FormDefinitionConsistencyException;
+use TYPO3\CMS\Form\Domain\Model\Renderable\AbstractCompositeRenderable;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+
+/**
+ * A base class for "section-like" form parts like "Page" or "Section" (which
+ * is rendered as "Fieldset")
+ *
+ * This class contains multiple FormElements ({@link FormElementInterface}).
+ *
+ * Please see {@link FormDefinition} for an in-depth explanation.
+ *
+ * **This class is NOT meant to be sub classed by developers.**
+ * Scope: frontend
+ */
+abstract class AbstractSection extends AbstractCompositeRenderable
+{
+
+    /**
+     * Constructor. Needs the identifier and type of this element
+     *
+     * @param string $identifier The Section identifier
+     * @param string $type The Section type
+     * @throws IdentifierNotValidException if the identifier was no non-empty string
+     * @api
+     */
+    public function __construct(string $identifier, string $type)
+    {
+        if (!is_string($identifier) || strlen($identifier) === 0) {
+            throw new IdentifierNotValidException('The given identifier was not a string or the string was empty.', 1477082501);
+        }
+
+        $this->identifier = $identifier;
+        $this->type = $type;
+    }
+
+    /**
+     * Get the child Form Elements
+     *
+     * @return FormElementInterface[] The Page's elements
+     * @api
+     */
+    public function getElements(): array
+    {
+        return $this->renderables;
+    }
+
+    /**
+     * Get the child Form Elements
+     *
+     * @return FormElementInterface[] The Page's elements
+     * @api
+     */
+    public function getElementsRecursively(): array
+    {
+        return $this->getRenderablesRecursively();
+    }
+
+    /**
+     * Add a new form element at the end of the section
+     *
+     * @param FormElementInterface $formElement The form element to add
+     * @return void
+     * @throws FormDefinitionConsistencyException if FormElement is already added to a section
+     * @api
+     */
+    public function addElement(FormElementInterface $formElement)
+    {
+        $this->addRenderable($formElement);
+    }
+
+    /**
+     * Create a form element with the given $identifier and attach it to this section/page.
+     *
+     * - Create Form Element object based on the given $typeName
+     * - set defaults inside the Form Element (based on the parent form's field defaults)
+     * - attach Form Element to this Section/Page
+     * - return the newly created Form Element object
+     *
+     *
+     * @param string $identifier Identifier of the new form element
+     * @param string $typeName type of the new form element
+     * @return FormElementInterface the newly created form element
+     * @throws TypeDefinitionNotFoundException
+     * @throws TypeDefinitionNotValidException
+     * @api
+     */
+    public function createElement(string $identifier, string $typeName): FormElementInterface
+    {
+        $formDefinition = $this->getRootForm();
+
+        $typeDefinitions = $formDefinition->getTypeDefinitions();
+        if (isset($typeDefinitions[$typeName])) {
+            $typeDefinition = $typeDefinitions[$typeName];
+        } else {
+            $element = GeneralUtility::makeInstance(ObjectManager::class)
+                ->get(UnknownFormElement::class, $identifier, $typeName);
+            $this->addElement($element);
+            return $element;
+        }
+
+        if (!isset($typeDefinition['implementationClassName'])) {
+            throw new TypeDefinitionNotFoundException(sprintf('The "implementationClassName" was not set in type definition "%s".', $typeName), 1325689855);
+        }
+
+        $implementationClassName = $typeDefinition['implementationClassName'];
+        $element = GeneralUtility::makeInstance(ObjectManager::class)
+            ->get($implementationClassName, $identifier, $typeName);
+        if (!$element instanceof FormElementInterface) {
+            throw new TypeDefinitionNotValidException(sprintf('The "implementationClassName" for element "%s" ("%s") does not implement the FormElementInterface.', $identifier, $implementationClassName), 1327318156);
+        }
+        unset($typeDefinition['implementationClassName']);
+
+        $this->addElement($element);
+        $element->setOptions($typeDefinition);
+
+        $element->initializeFormElement();
+        return $element;
+    }
+
+    /**
+     * Move FormElement $element before $referenceElement.
+     *
+     * Both $element and $referenceElement must be direct descendants of this Section/Page.
+     *
+     * @param FormElementInterface $elementToMove
+     * @param FormElementInterface $referenceElement
+     * @return void
+     * @api
+     */
+    public function moveElementBefore(FormElementInterface $elementToMove, FormElementInterface $referenceElement)
+    {
+        $this->moveRenderableBefore($elementToMove, $referenceElement);
+    }
+
+    /**
+     * Move FormElement $element after $referenceElement
+     *
+     * Both $element and $referenceElement must be direct descendants of this Section/Page.
+     *
+     * @param FormElementInterface $elementToMove
+     * @param FormElementInterface $referenceElement
+     * @return void
+     * @api
+     */
+    public function moveElementAfter(FormElementInterface $elementToMove, FormElementInterface $referenceElement)
+    {
+        $this->moveRenderableAfter($elementToMove, $referenceElement);
+    }
+
+    /**
+     * Remove $elementToRemove from this Section/Page
+     *
+     * @param FormElementInterface $elementToRemove
+     * @return void
+     * @api
+     */
+    public function removeElement(FormElementInterface $elementToRemove)
+    {
+        $this->removeRenderable($elementToRemove);
+    }
+
+    /**
+     * This callback is invoked by the FormRuntime whenever values are mapped and validated
+     * (after a form page was submitted)
+     * @see FormRuntime::mapAndValidate()
+     *
+     * @param FormRuntime $formRuntime
+     * @param mixed $elementValue submitted value of the element *before post processing*
+     * @param array $requestArguments submitted raw request values
+     * @return void
+     * @api
+     */
+    public function onSubmit(FormRuntime $formRuntime, &$elementValue, array $requestArguments = [])
+    {
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/FormElements/AdvancedPassword.php b/typo3/sysext/form/Classes/Domain/Model/FormElements/AdvancedPassword.php
new file mode 100644
index 0000000000000000000000000000000000000000..206abb9fd80e683bc01392757726a6e29d836d7d
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/FormElements/AdvancedPassword.php
@@ -0,0 +1,53 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\FormElements;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Error\Error;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+
+/**
+ * A password with confirmation form element
+ *
+ * Scope: frontend
+ */
+class AdvancedPassword extends AbstractFormElement
+{
+
+    /**
+     * This callback is invoked by the FormRuntime whenever values are mapped and validated
+     * (after a form page was submitted)
+     *
+     * @param FormRuntime $formRuntime
+     * @param mixed $elementValue submitted value of the element *before post processing*
+     * @param array $requestArguments submitted raw request values
+     * @return void
+     * @see FormRuntime::mapAndValidate()
+     * @internal
+     */
+    public function onSubmit(FormRuntime $formRuntime, &$elementValue, array $requestArguments = [])
+    {
+        if ($elementValue['password'] !== $elementValue['confirmation']) {
+            $processingRule = $this->getRootForm()->getProcessingRule($this->getIdentifier());
+            $processingRule->getProcessingMessages()->addError(
+                GeneralUtility::makeInstance(ObjectManager::class)
+                    ->get(Error::class, 'Password doesn\'t match confirmation', 1334768052)
+            );
+        }
+        $elementValue = $elementValue['password'];
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Filter/IntegerFilter.php b/typo3/sysext/form/Classes/Domain/Model/FormElements/DatePicker.php
similarity index 61%
rename from typo3/sysext/form/Classes/Domain/Filter/IntegerFilter.php
rename to typo3/sysext/form/Classes/Domain/Model/FormElements/DatePicker.php
index 24bc8fe801032e220f50946cf032773b8b9dff36..5aea0b31c05670a8e3e3d22ed18415e4689802d0 100644
--- a/typo3/sysext/form/Classes/Domain/Filter/IntegerFilter.php
+++ b/typo3/sysext/form/Classes/Domain/Model/FormElements/DatePicker.php
@@ -1,5 +1,6 @@
 <?php
-namespace TYPO3\CMS\Form\Domain\Filter;
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\FormElements;
 
 /*
  * This file is part of the TYPO3 CMS project.
@@ -15,18 +16,19 @@ namespace TYPO3\CMS\Form\Domain\Filter;
  */
 
 /**
- * Integer filter
+ * A date picker form element
+ *
+ * Scope: frontend
  */
-class IntegerFilter extends AbstractFilter implements FilterInterface
+class DatePicker extends AbstractFormElement
 {
+
     /**
-     * Cast to integer
-     *
-     * @param string $value
-     * @return string
+     * @return void
+     * @internal
      */
-    public function filter($value)
+    public function initializeFormElement()
     {
-        return (int)((string)$value);
+        $this->setDataType('DateTime');
     }
 }
diff --git a/typo3/sysext/form/Classes/Domain/Model/FormElements/FileUpload.php b/typo3/sysext/form/Classes/Domain/Model/FormElements/FileUpload.php
new file mode 100644
index 0000000000000000000000000000000000000000..0bfe7132aa2c4c0677b710f46d4509be70ffd005
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/FormElements/FileUpload.php
@@ -0,0 +1,109 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\FormElements;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Resource\ResourceFactory;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\PathUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Form\Mvc\Property\TypeConverter\UploadedFileReferenceConverter;
+use TYPO3\CMS\Form\Mvc\Validation\MimeTypeValidator;
+
+/**
+ * A generic file upload form element
+ *
+ * Scope: frontend
+ */
+class FileUpload extends AbstractFormElement
+{
+
+    /**
+     * @return void
+     * @internal
+     */
+    public function initializeFormElement()
+    {
+        $this->setDataType('TYPO3\CMS\Extbase\Domain\Model\FileReference');
+    }
+
+    /**
+     * Set the property mapping configuration for the file upload element.
+     * * Add the UploadedFileReferenceConverter to convert an uploaded file to an
+     *   FileReference.
+     * * Add the MimeTypeValidator to the UploadedFileReferenceConverter to
+     *   delete non valid filetypes directly.
+     * * Setup the storage:
+     *   If the property "saveToFileMount" exist for this element it will be used.
+     *   If this file mount or the property "saveToFileMount" does not exist
+     *   the folder in which the form definition lies (persistence identifier) will be used.
+     *   If the form is generated programmatically and therefore no
+     *   persistence identifier exist the default storage "1:/user_upload/" will be used.
+     *
+     * @return void
+     * @internal
+     * @todo: could we find a not so ugly solution for that?
+     */
+    public function onBuildingFinished()
+    {
+        /** @var \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration $propertyMappingConfiguration */
+        $propertyMappingConfiguration = $this->getRootForm()->getProcessingRule($this->getIdentifier())->getPropertyMappingConfiguration();
+
+        $mimeTypeValidator = GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(MimeTypeValidator::class, ['allowedMimeTypes' => $this->properties['allowedMimeTypes']]);
+        $uploadConfiguration = [
+            UploadedFileReferenceConverter::CONFIGURATION_FILE_VALIDATORS => [$mimeTypeValidator],
+            UploadedFileReferenceConverter::CONFIGURATION_UPLOAD_CONFLICT_MODE => 'rename',
+        ];
+
+        $saveToFileMountIdentifier = (isset($this->properties['saveToFileMount'])) ? $this->properties['saveToFileMount'] : null;
+        if ($this->checkSaveFileMountAccess($saveToFileMountIdentifier)) {
+            $uploadConfiguration[UploadedFileReferenceConverter::CONFIGURATION_UPLOAD_FOLDER] = $saveToFileMountIdentifier;
+        } else {
+            $persistenceIdentifier = $this->getRootForm()->getPersistenceIdentifier();
+            if (!empty($persistenceIdentifier)) {
+                $pathinfo = PathUtility::pathinfo($persistenceIdentifier);
+                $saveToFileMountIdentifier  = $pathinfo['dirname'];
+                if ($this->checkSaveFileMountAccess($saveToFileMountIdentifier)) {
+                    $uploadConfiguration[UploadedFileReferenceConverter::CONFIGURATION_UPLOAD_FOLDER] = $saveToFileMountIdentifier;
+                }
+            }
+        }
+
+        $propertyMappingConfiguration->setTypeConverterOptions(UploadedFileReferenceConverter::class, $uploadConfiguration);
+    }
+
+    /**
+     * @param string $saveToFileMountIdentifier
+     * @return bool
+     * @internal
+     */
+    protected function checkSaveFileMountAccess(string $saveToFileMountIdentifier): bool
+    {
+        if (empty($saveToFileMountIdentifier)) {
+            return false;
+        }
+
+        $resourceFactory = GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(ResourceFactory::class);
+
+        try {
+            $resourceFactory->getFolderObjectFromCombinedIdentifier($saveToFileMountIdentifier);
+            return true;
+        } catch (\InvalidArgumentException $e) {
+            return false;
+        }
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/FormElements/FormElementInterface.php b/typo3/sysext/form/Classes/Domain/Model/FormElements/FormElementInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..15413677133de8b9e36982148548888d6399df2b
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/FormElements/FormElementInterface.php
@@ -0,0 +1,147 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\FormElements;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+
+/**
+ * A base form element interface, which can be the starting point for creating
+ * custom (PHP-based) Form Elements.
+ *
+ * A *FormElement* is a part of a *Page*, which in turn is part of a FormDefinition.
+ * See {@link FormDefinition} for an in-depth explanation.
+ *
+ * **Often, you should rather subclass {@link AbstractFormElement} instead of
+ * implementing this interface.**
+ *
+ * Scope: frontend
+ */
+interface FormElementInterface extends RenderableInterface
+{
+
+    /**
+     * Will be called as soon as the element is (tried to be) added to a form
+     * @see registerInFormIfPossible()
+     *
+     * @return void
+     * @internal
+     */
+    public function initializeFormElement();
+
+    /**
+     * Returns a unique identifier of this element.
+     * While element identifiers are only unique within one form,
+     * this includes the identifier of the form itself, making it "globally" unique
+     *
+     * @return string the "globally" unique identifier of this element
+     * @api
+     */
+    public function getUniqueIdentifier(): string;
+
+    /**
+     * Get the default value with which the Form Element should be initialized
+     * during display.
+     *
+     * @return mixed the default value for this Form Element
+     * @api
+     */
+    public function getDefaultValue();
+
+    /**
+     * Set the default value with which the Form Element should be initialized
+     * during display.
+     *
+     * @param mixed $defaultValue the default value for this Form Element
+     * @api
+     */
+    public function setDefaultValue($defaultValue);
+
+    /**
+     * Set an element-specific configuration property.
+     *
+     * @param string $key
+     * @param mixed $value
+     * @return void
+     * @api
+     */
+    public function setProperty(string $key, $value);
+
+    /**
+     * Get all element-specific configuration properties
+     *
+     * @return array
+     * @api
+     */
+    public function getProperties(): array;
+
+    /**
+     * Set a rendering option
+     *
+     * @param string $key
+     * @param mixed $value
+     * @api
+     */
+    public function setRenderingOption(string $key, $value);
+
+    /**
+     * Returns the child validators of the ConjunctionValidator that is registered for this element
+     *
+     * @return \SplObjectStorage<ValidatorInterface>
+     * @internal
+     */
+    public function getValidators(): \SplObjectStorage;
+
+    /**
+     * Registers a validator for this element
+     *
+     * @param ValidatorInterface $validator
+     * @return void
+     * @api
+     */
+    public function addValidator(ValidatorInterface $validator);
+
+    /**
+     * Set the target data type for this element
+     *
+     * @param string $dataType the target data type
+     * @return void
+     * @api
+     */
+    public function setDataType(string $dataType);
+
+    /**
+     * Whether or not this element is required
+     *
+     * @return bool
+     * @api
+     */
+    public function isRequired(): bool;
+
+    /**
+     * This callback is invoked by the FormRuntime whenever values are mapped and validated
+     * (after a form page was submitted)
+     *
+     * @param FormRuntime $formRuntime
+     * @param mixed $elementValue submitted value of the element *before post processing*
+     * @param array $requestArguments submitted raw request values
+     * @return void
+     * @see FormRuntime::mapAndValidate()
+     * @api
+     */
+    public function onSubmit(FormRuntime $formRuntime, &$elementValue, array $requestArguments = []);
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/FormElements/GenericFormElement.php b/typo3/sysext/form/Classes/Domain/Model/FormElements/GenericFormElement.php
new file mode 100644
index 0000000000000000000000000000000000000000..05119f810076cf6d9dbe5ebd897ebf0aefef2369
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/FormElements/GenericFormElement.php
@@ -0,0 +1,26 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\FormElements;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * A generic form element
+ *
+ * Scope: frontend
+ * @api
+ */
+class GenericFormElement extends AbstractFormElement
+{
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/FormElements/Page.php b/typo3/sysext/form/Classes/Domain/Model/FormElements/Page.php
new file mode 100644
index 0000000000000000000000000000000000000000..568c23c3c71fdc2e9ec0dda5e67a293fe74b0fa6
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/FormElements/Page.php
@@ -0,0 +1,68 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\FormElements;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Model\FormDefinition;
+use TYPO3\CMS\Form\Domain\Model\Renderable\CompositeRenderableInterface;
+use TYPO3\CMS\Form\Exception as FormException;
+
+/**
+ * A Page, being part of a bigger FormDefinition. It contains numerous FormElements
+ * as children.
+ *
+ * A FormDefinition consists of multiple Pages, where only one page is visible
+ * at any given time.
+ *
+ * Most of the API of this object is implemented in {@link AbstractSection},
+ * so make sure to review this class as well.
+ *
+ * Please see {@link FormDefinition} for an in-depth explanation.
+ *
+ * Scope: frontend
+ * **This class is NOT meant to be sub classed by developers.**
+ */
+class Page extends AbstractSection
+{
+
+    /**
+     * Constructor. Needs this Page's identifier
+     *
+     * @param string $identifier The Page's identifier
+     * @param string $type The Page's type
+     * @throws \TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException if the identifier was no non-empty string
+     * @api
+     */
+    public function __construct(string $identifier, string $type = 'Page')
+    {
+        parent::__construct($identifier, $type);
+    }
+
+    /**
+     * Set the parent renderable
+     *
+     * @param CompositeRenderableInterface $parentRenderable
+     * @return void
+     * @throws FormException
+     * @api
+     */
+    public function setParentRenderable(CompositeRenderableInterface $parentRenderable)
+    {
+        if (!($parentRenderable instanceof FormDefinition)) {
+            throw new FormException(sprintf('The specified parentRenderable must be a FormDefinition, got "%s"', is_object($parentRenderable) ? get_class($parentRenderable) : gettype($parentRenderable)), 1329233747);
+        }
+        parent::setParentRenderable($parentRenderable);
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/FormElements/Section.php b/typo3/sysext/form/Classes/Domain/Model/FormElements/Section.php
new file mode 100644
index 0000000000000000000000000000000000000000..61ee7864f71939a3a9e5412164389debf138b7a7
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/FormElements/Section.php
@@ -0,0 +1,166 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\FormElements;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator;
+use TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface;
+
+/**
+ * A Section, being part of a bigger Page
+ *
+ * This class contains multiple FormElements ({@link FormElementInterface}).
+ *
+ * Please see {@link FormDefinition} for an in-depth explanation.
+ *
+ * Scope: frontend
+ * **This class is NOT meant to be sub classed by developers.**
+ */
+class Section extends AbstractSection implements FormElementInterface
+{
+
+    /**
+     * @var array
+     */
+    protected $properties = [];
+
+    /**
+     * Will be called as soon as the element is (tried to be) added to a form
+     * @see registerInFormIfPossible()
+     *
+     * @return void
+     * @internal
+     */
+    public function initializeFormElement()
+    {
+    }
+
+    /**
+     * Returns a unique identifier of this element.
+     * While element identifiers are only unique within one form,
+     * this includes the identifier of the form itself, making it "globally" unique
+     *
+     * @return string the "globally" unique identifier of this element
+     * @api
+     */
+    public function getUniqueIdentifier(): string
+    {
+        $formDefinition = $this->getRootForm();
+        return sprintf('%s-%s', $formDefinition->getIdentifier(), $this->identifier);
+    }
+
+    /**
+     * Get the default value with which the Form Element should be initialized
+     * during display.
+     * Note: This is currently not used for section elements
+     *
+     * @return mixed the default value for this Form Element
+     * @api
+     */
+    public function getDefaultValue()
+    {
+        return null;
+    }
+
+    /**
+     * Set the default value with which the Form Element should be initialized
+     * during display.
+     * Note: This is currently ignored for section elements
+     *
+     * @param mixed $defaultValue the default value for this Form Element
+     * @api
+     */
+    public function setDefaultValue($defaultValue)
+    {
+    }
+
+    /**
+     * Get all element-specific configuration properties
+     *
+     * @return array
+     * @api
+     */
+    public function getProperties(): array
+    {
+        return $this->properties;
+    }
+
+    /**
+     * Set an element-specific configuration property.
+     *
+     * @param string $key
+     * @param mixed $value
+     * @return void
+     * @api
+     */
+    public function setProperty(string $key, $value)
+    {
+        $this->properties[$key] = $value;
+    }
+
+    /**
+     * Set the rendering option $key to $value.
+     *
+     * @param string $key
+     * @param mixed $value
+     * @return mixed
+     * @api
+     */
+    public function setRenderingOption(string $key, $value)
+    {
+        $this->renderingOptions[$key] = $value;
+    }
+
+    /**
+     * Get all validators on the element
+     *
+     * @return \SplObjectStorage
+     * @internal
+     */
+    public function getValidators(): \SplObjectStorage
+    {
+        $formDefinition = $this->getRootForm();
+        return $formDefinition->getProcessingRule($this->getIdentifier())->getValidators();
+    }
+
+    /**
+     * Add a validator to the element
+     *
+     * @param ValidatorInterface $validator
+     * @return void
+     * @api
+     */
+    public function addValidator(ValidatorInterface $validator)
+    {
+        $formDefinition = $this->getRootForm();
+        $formDefinition->getProcessingRule($this->getIdentifier())->addValidator($validator);
+    }
+
+    /**
+     * Whether or not this element is required
+     *
+     * @return bool
+     * @api
+     */
+    public function isRequired(): bool
+    {
+        foreach ($this->getValidators() as $validator) {
+            if ($validator instanceof NotEmptyValidator) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/FormElements/UnknownFormElement.php b/typo3/sysext/form/Classes/Domain/Model/FormElements/UnknownFormElement.php
new file mode 100644
index 0000000000000000000000000000000000000000..08ab78e29be04160e39ee73a746b6489e1b2157c
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/FormElements/UnknownFormElement.php
@@ -0,0 +1,147 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\FormElements;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException;
+use TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable;
+use TYPO3\CMS\Form\Domain\Renderer\UnknownFormElementRenderer;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+
+/**
+ * A Form Element that has no definition.
+ *
+ * Scope: frontend
+ */
+class UnknownFormElement extends AbstractRenderable implements FormElementInterface
+{
+
+    /**
+     * Constructor. Needs this FormElement's identifier and the FormElement type
+     *
+     * @param string $identifier The FormElement's identifier
+     * @param string $type The Form Element Type
+     * @throws IdentifierNotValidException
+     * @api
+     */
+    public function __construct(string $identifier, string $type)
+    {
+        if (!is_string($identifier) || strlen($identifier) === 0) {
+            throw new IdentifierNotValidException('The given identifier was not a string or the string was empty.', 1382364370);
+        }
+        $this->identifier = $identifier;
+        $this->type = $type;
+    }
+
+    /**
+     * Returns a unique identifier of this element.
+     * While element identifiers are only unique within one form,
+     * this includes the identifier of the form itself, making it "globally" unique
+     *
+     * @return string the "globally" unique identifier of this element
+     * @api
+     */
+    public function getUniqueIdentifier(): string
+    {
+        $formDefinition = $this->getRootForm();
+        $uniqueIdentifier = sprintf('%s-%s', $formDefinition->getIdentifier(), $this->identifier);
+        $uniqueIdentifier = preg_replace('/[^a-zA-Z0-9-_]/', '_', $uniqueIdentifier);
+        return lcfirst($uniqueIdentifier);
+    }
+
+    /**
+     * Unknown Form Elements are rendered with the UnknownFormElementRenderer
+     *
+     * @return string the renderer class name
+     * @internal
+     */
+    public function getRendererClassName(): string
+    {
+        return UnknownFormElementRenderer::class;
+    }
+
+    /**
+     * Not used in this implementation
+     *
+     * @return void
+     * @internal
+     */
+    public function initializeFormElement()
+    {
+    }
+
+    /**
+     * @return mixed the default value for this Form Element
+     * @internal
+     */
+    public function getDefaultValue()
+    {
+        return null;
+    }
+
+    /**
+     * Not used in this implementation
+     *
+     * @param mixed $defaultValue the default value for this Form Element
+     * @internal
+     */
+    public function setDefaultValue($defaultValue)
+    {
+    }
+
+    /**
+     * Not used in this implementation
+     *
+     * @param string $key
+     * @param mixed $value
+     * @return void
+     * @internal
+     */
+    public function setProperty(string $key, $value)
+    {
+    }
+
+    /**
+     * @return array
+     * @internal
+     */
+    public function getProperties(): array
+    {
+        return [];
+    }
+
+    /**
+     * @return bool
+     * @internal
+     */
+    public function isRequired(): bool
+    {
+        return false;
+    }
+
+    /**
+     * Not used in this implementation
+     *
+     * @param FormRuntime $formRuntime
+     * @param mixed $elementValue submitted value of the element *before post processing*
+     * @param array $requestArguments submitted raw request values
+     * @return void
+     * @see FormRuntime::mapAndValidate()
+     * @internal
+     */
+    public function onSubmit(FormRuntime $formRuntime, &$elementValue, array $requestArguments = [])
+    {
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/AbstractJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/AbstractJsonElement.php
deleted file mode 100644
index f61431d417c4325a64a99ccf9b308313d26d5544..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/AbstractJsonElement.php
+++ /dev/null
@@ -1,178 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON element abstract
- */
-class AbstractJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = '';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [];
-
-    /**
-     * Child elements allowed withing this element
-     *
-     * Some elements like select handle their own child elements
-     *
-     * @var bool
-     */
-    protected $childElementsAllowed = true;
-
-    /**
-     * Set all the parameters for this object
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    public function setParameters(array $parameters)
-    {
-        foreach ($this->configuration as $key => $value) {
-            switch ($key) {
-                case 'attributes':
-                    $this->setAttributes($parameters);
-                    break;
-                case 'filters':
-                    $this->setFilters($parameters);
-                    break;
-                case 'label':
-                    $this->setLabel($parameters);
-                    break;
-                case 'layout':
-                    $this->setLayout($parameters);
-                    break;
-                case 'validation':
-                    $this->setValidation($parameters);
-                    break;
-                }
-        }
-    }
-
-    /**
-     * Check if child elements are allowed within this element
-     *
-     * @return bool TRUE if allowed
-     */
-    public function childElementsAllowed()
-    {
-        return $this->childElementsAllowed;
-    }
-
-    /**
-     * Set the attributes according to the allowed attributes of this element
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setAttributes(array $parameters)
-    {
-        foreach ($this->allowedAttributes as $allowedAttribute) {
-            if (isset($parameters[$allowedAttribute])) {
-                $this->configuration['attributes'][$allowedAttribute] = $parameters[$allowedAttribute];
-            } elseif (!isset($this->configuration['attributes'][$allowedAttribute])) {
-                $this->configuration['attributes'][$allowedAttribute] = '';
-            }
-        }
-    }
-
-    /**
-     * Set the filters of the element
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setFilters(array $parameters)
-    {
-        if (isset($parameters['filters.']) && is_array($parameters['filters.'])) {
-            $filters = $parameters['filters.'];
-            foreach ($filters as $key => $filterName) {
-                if ((int)$key && strpos($key, '.') === false) {
-                    $filterConfiguration = [];
-                    if (isset($filters[$key . '.'])) {
-                        $filterConfiguration = $filters[$key . '.'];
-                    }
-                    $this->configuration['filters'][$filterName] = $filterConfiguration;
-                }
-            }
-        } else {
-            $this->configuration['filters'] = new \stdClass();
-        }
-    }
-
-    /**
-     * Set the label of the element
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setLabel(array $parameters)
-    {
-        if (isset($parameters['label']) && !isset($parameters['label.'])) {
-            $this->configuration['label']['value'] = $parameters['label'];
-        } elseif (!isset($parameters['label']) && isset($parameters['label.'])) {
-            $this->configuration['label']['value'] = $parameters['label.']['value'];
-        }
-    }
-
-    /**
-     * Set the layout of the element
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setLayout(array $parameters)
-    {
-        if (isset($parameters['layout'])) {
-            if ($this->configuration['layout'] === 'front') {
-                $this->configuration['layout'] = 'back';
-            } else {
-                $this->configuration['layout'] = 'front';
-            }
-        }
-    }
-
-    /**
-     * Set the validation rules for the element
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setValidation(array $parameters)
-    {
-        if (isset($parameters['validation']) && is_array($parameters['validation'])) {
-            $this->configuration['validation'] = $parameters['validation'];
-        } else {
-            $this->configuration['validation'] = new \stdClass();
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/ButtonJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/ButtonJsonElement.php
deleted file mode 100644
index 8d1520a680e5f3c1afed729e4f8338e4242b4f5a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/ButtonJsonElement.php
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON button
- */
-class ButtonJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-basic-button';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [
-            'type' => 'button'
-        ],
-        'filters' => [],
-        'label' => [
-            'value' => ''
-        ],
-        'layout' => 'front',
-        'validation' => []
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'accesskey',
-        'class',
-        'contenteditable',
-        'contextmenu',
-        'dir',
-        'draggable',
-        'dropzone',
-        'hidden',
-        'id',
-        'lang',
-        'spellcheck',
-        'style',
-        'tabindex',
-        'title',
-        'translate',
-        /* element specific attributes */
-        'autofocus',
-        'disabled',
-        'name',
-        'type',
-        'value'
-    ];
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/CheckboxGroupJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/CheckboxGroupJsonElement.php
deleted file mode 100644
index f9795d072d9d48f1803e1150d8afa143148e2797..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/CheckboxGroupJsonElement.php
+++ /dev/null
@@ -1,120 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-use TYPO3\CMS\Core\Utility\ArrayUtility;
-
-/**
- * JSON checkboxgroup
- */
-class CheckboxGroupJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\FieldsetJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-predefined-checkboxgroup';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [],
-        'legend' => [
-            'value' => ''
-        ],
-        'options' => [],
-        'various' => [
-            'name' => ''
-        ],
-        'validation' => []
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'class',
-        'dir',
-        'id',
-        'lang',
-        'style'
-    ];
-
-    /**
-     * Set all the parameters for this object
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     * @see \TYPO3\CMS\Form\Domain\Model\Json\FieldsetJsonElement::setParameters()
-     */
-    public function setParameters(array $parameters)
-    {
-        parent::setParameters($parameters);
-        $this->setOptions($parameters);
-        $this->setVarious($parameters);
-    }
-
-    /**
-     * Set the options for this object
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setOptions(array $parameters)
-    {
-        if (is_array($parameters)) {
-            $keys = ArrayUtility::filterAndSortByNumericKeys($parameters);
-            foreach ($keys as $key) {
-                $class = $parameters[$key];
-                if ((int)$key && strpos($key, '.') === false) {
-                    if (isset($parameters[$key . '.']) && $class === 'CHECKBOX') {
-                        $childElementArguments = $parameters[$key . '.'];
-                        if (isset($childElementArguments['checked'])) {
-                            $childElementArguments['attributes']['selected'] = 'selected';
-                            unset($childElementArguments['checked']);
-                        }
-                        if (isset($childElementArguments['value'])) {
-                            $childElementArguments['attributes']['value'] = $childElementArguments['value'];
-                            unset($childElementArguments['value']);
-                        }
-                        if (isset($childElementArguments['label.'])) {
-                            $childElementArguments['text'] = $childElementArguments['label.']['value'];
-                            unset($childElementArguments['label.']);
-                        }
-                        $this->configuration['options'][] = $childElementArguments;
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Set the various properties for this object
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setVarious(array $parameters)
-    {
-        if (isset($parameters['name'])) {
-            $this->configuration['various']['name'] = $parameters['name'];
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/CheckboxJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/CheckboxJsonElement.php
deleted file mode 100644
index 68b38864902c775f0549d0a60368cde65f8a6b6c..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/CheckboxJsonElement.php
+++ /dev/null
@@ -1,77 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON checkbox
- */
-class CheckboxJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-basic-checkbox';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [
-            'type' => 'checkbox'
-        ],
-        'filters' => [],
-        'label' => [
-            'value' => ''
-        ],
-        'layout' => 'back',
-        'validation' => []
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'accesskey',
-        'class',
-        'contenteditable',
-        'contextmenu',
-        'dir',
-        'draggable',
-        'dropzone',
-        'hidden',
-        'id',
-        'lang',
-        'spellcheck',
-        'style',
-        'tabindex',
-        'title',
-        'translate',
-        /* element specific attributes */
-        'autofocus',
-        'checked',
-        'disabled',
-        'name',
-        'readonly',
-        'required',
-        'type',
-        'value'
-    ];
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/ContainerJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/ContainerJsonElement.php
deleted file mode 100644
index 32f477f7842fdeb8be664538196fd28d033fb88e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/ContainerJsonElement.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON container abstract
- */
-class ContainerJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement
-{
-    /**
-     * The items within this container
-     *
-     * @var array
-     */
-    public $elementContainer = [
-        'hasDragAndDrop' => true,
-        'items' => []
-    ];
-
-    /**
-     * Add an element to this container
-     *
-     * @param \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement $element The element to add
-     * @return void
-     */
-    public function addElement(\TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement $element)
-    {
-        $this->elementContainer['items'][] = $element;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/FieldsetJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/FieldsetJsonElement.php
deleted file mode 100644
index 60283e036aefb5c852e5fbdff584b3ea08d8ef07..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/FieldsetJsonElement.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON fieldset
- */
-class FieldsetJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\ContainerJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-basic-fieldset';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [],
-        'legend' => [
-            'value' => ''
-        ]
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'class',
-        'dir',
-        'id',
-        'lang',
-        'style'
-    ];
-
-    /**
-     * Set all the parameters for this object
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     * @see \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement::setParameters()
-     */
-    public function setParameters(array $parameters)
-    {
-        parent::setParameters($parameters);
-        $this->setLegend($parameters);
-    }
-
-    /**
-     * Set the legend for the element
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setLegend(array $parameters)
-    {
-        if (isset($parameters['legend']) && !isset($parameters['legend.'])) {
-            $this->configuration['legend']['value'] = $parameters['legend'];
-        } elseif (!isset($parameters['legend']) && isset($parameters['legend.'])) {
-            $this->configuration['legend']['value'] = $parameters['legend.']['value'];
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/FileuploadJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/FileuploadJsonElement.php
deleted file mode 100644
index 50cc8ae2c99a0ed0a47e5457af01251133524835..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/FileuploadJsonElement.php
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON Fileupload
- */
-class FileuploadJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-basic-fileupload';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [
-            'type' => 'file'
-        ],
-        'filters' => [],
-        'label' => [
-            'value' => ''
-        ],
-        'layout' => 'front',
-        'validation' => []
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'accesskey',
-        'class',
-        'contenteditable',
-        'contextmenu',
-        'dir',
-        'draggable',
-        'dropzone',
-        'hidden',
-        'id',
-        'lang',
-        'spellcheck',
-        'style',
-        'tabindex',
-        'title',
-        'translate',
-        /* element specific attributes */
-        'accept',
-        'autofocus',
-        'disabled',
-        'multiple',
-        'name',
-        'readonly',
-        'required',
-        'type',
-        'value'
-    ];
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/FormJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/FormJsonElement.php
deleted file mode 100644
index 312ce8bc827ba2198ce5ec8683b5c509e448d683..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/FormJsonElement.php
+++ /dev/null
@@ -1,141 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON form
- */
-class FormJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\ContainerJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-basic-form';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [],
-        'prefix' => 'tx_form',
-        'confirmation' => true,
-        'postProcessor' => []
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'accesskey',
-        'class',
-        'contenteditable',
-        'contextmenu',
-        'dir',
-        'draggable',
-        'dropzone',
-        'hidden',
-        'id',
-        'lang',
-        'spellcheck',
-        'style',
-        'tabindex',
-        'title',
-        'translate',
-        /* element specific attributes */
-        'accept',
-        'accept-charset',
-        'action',
-        'autocomplete',
-        'enctype',
-        'method',
-        'novalidate'
-    ];
-
-    /**
-     * Set all the parameters for this object
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     * @see \TYPO3\CMS\Form\Domain\Model\Json\ContainerJsonElement::setParameters()
-     */
-    public function setParameters(array $parameters)
-    {
-        parent::setParameters($parameters);
-        $this->setPrefix($parameters);
-        $this->setConfirmation($parameters);
-        $this->setPostProcessors($parameters);
-    }
-
-    /**
-     * Set the confirmation message boolean
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setConfirmation(array $parameters)
-    {
-        if (isset($parameters['confirmation'])) {
-            $this->configuration['confirmation'] = $parameters['confirmation'];
-        }
-    }
-
-    /**
-     * Set the post processors and their configuration
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setPostProcessors(array $parameters)
-    {
-        if (isset($parameters['postProcessor.']) && is_array($parameters['postProcessor.'])) {
-            $postProcessors = $parameters['postProcessor.'];
-            foreach ($postProcessors as $key => $postProcessorName) {
-                if ((int)$key && strpos($key, '.') === false) {
-                    $postProcessorConfiguration = [];
-                    if (isset($postProcessors[$key . '.'])) {
-                        $postProcessorConfiguration = $postProcessors[$key . '.'];
-                    }
-                    $this->configuration['postProcessor'][$postProcessorName] = $postProcessorConfiguration;
-                }
-            }
-        } else {
-            $this->configuration['postProcessor'] = [
-                'mail' => [
-                    'recipientEmail' => '',
-                    'senderEmail' => ''
-                ]
-            ];
-        }
-    }
-
-    /**
-     * Set the prefix
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setPrefix(array $parameters)
-    {
-        if (isset($parameters['prefix'])) {
-            $this->configuration['prefix'] = $parameters['prefix'];
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/HeaderJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/HeaderJsonElement.php
deleted file mode 100644
index 2461799969f8c1cfe87b29af9f04ce58f0c91c83..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/HeaderJsonElement.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON header
- */
-class HeaderJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-content-header';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [],
-        'various' => [
-            'headingSize' => 'h1',
-            'content' => ''
-        ]
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'class',
-        'dir',
-        'id',
-        'lang',
-        'style',
-        'title'
-    ];
-
-    /**
-     * Set all the parameters for this object
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     * @see \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement::setParameters()
-     */
-    public function setParameters(array $parameters)
-    {
-        parent::setParameters($parameters);
-        $this->setVarious($parameters);
-    }
-
-    /**
-     * Set the various properties for the element
-     *
-     * For this element this is the headingsize and the value
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setVarious(array $parameters)
-    {
-        if (isset($parameters['headingSize'])) {
-            if (preg_match('#^h[1-5]$#', $parameters['headingSize'])) {
-                $this->configuration['various']['headingSize'] = $parameters['headingSize'];
-            }
-        }
-        if (isset($parameters['content'])) {
-            $this->configuration['various']['content'] = $parameters['content'];
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/HiddenJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/HiddenJsonElement.php
deleted file mode 100644
index 6c7f61cd554c7805a535e72f19f3a39ea8f436bb..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/HiddenJsonElement.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON hidden
- */
-class HiddenJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-basic-hidden';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [
-            'type' => 'hidden'
-        ],
-        'filters' => [],
-        'label' => [
-            'value' => ''
-        ],
-        'layout' => 'front',
-        'validation' => []
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'accesskey',
-        'class',
-        'contenteditable',
-        'contextmenu',
-        'dir',
-        'draggable',
-        'dropzone',
-        'hidden',
-        'id',
-        'lang',
-        'spellcheck',
-        'style',
-        'tabindex',
-        'title',
-        'translate',
-        /* element specific attributes */
-        'name',
-        'type',
-        'value'
-    ];
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/NameJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/NameJsonElement.php
deleted file mode 100644
index 6f4ba0e573f3281ffdf2ef5d0b2f426a01e11261..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/NameJsonElement.php
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-use TYPO3\CMS\Core\Utility\ArrayUtility;
-
-/**
- * JSON name
- */
-class NameJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\FieldsetJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-predefined-name';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [],
-        'legend' => [
-            'value' => ''
-        ],
-        'various' => [
-            'prefix' => false,
-            'suffix' => false,
-            'middleName' => false
-        ]
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'class',
-        'dir',
-        'id',
-        'lang',
-        'style'
-    ];
-
-    /**
-     * Set all the parameters for this object
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     * @see \TYPO3\CMS\Form\Domain\Model\Json\FieldsetJsonElement::setParameters()
-     */
-    public function setParameters(array $parameters)
-    {
-        parent::setParameters($parameters);
-        $this->setVarious($parameters);
-    }
-
-    /**
-     * Set the various properties for the element
-     *
-     * For this element this is the prefix, suffix and middleName if they will
-     * be shown in the form
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setVarious(array $parameters)
-    {
-        if (is_array($parameters)) {
-            $keys = ArrayUtility::filterAndSortByNumericKeys($parameters);
-            foreach ($keys as $key) {
-                if ((int)$key && strpos($key, '.') === false) {
-                    if (isset($parameters[$key . '.'])) {
-                        $childElementArguments = $parameters[$key . '.'];
-                        if (in_array($childElementArguments['name'], ['prefix', 'suffix', 'middleName'])) {
-                            $this->configuration['various'][$childElementArguments['name']] = true;
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/PasswordJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/PasswordJsonElement.php
deleted file mode 100644
index 402d60995e3531b3b40e76721af575681ae1fd56..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/PasswordJsonElement.php
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON password
- */
-class PasswordJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-basic-password';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [
-            'type' => 'password'
-        ],
-        'filters' => [],
-        'label' => [
-            'value' => ''
-        ],
-        'layout' => 'front',
-        'validation' => []
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'accesskey',
-        'class',
-        'contenteditable',
-        'contextmenu',
-        'dir',
-        'draggable',
-        'dropzone',
-        'hidden',
-        'id',
-        'lang',
-        'spellcheck',
-        'style',
-        'tabindex',
-        'title',
-        'translate',
-        /* element specific attributes */
-        'autocomplete',
-        'autofocus',
-        'disabled',
-        'maxlength',
-        'minlength',
-        'name',
-        'pattern',
-        'placeholder',
-        'readonly',
-        'required',
-        'size',
-        'type',
-        'value'
-    ];
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/RadioGroupJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/RadioGroupJsonElement.php
deleted file mode 100644
index 27b6bff0f9eede0ec6daef40dbdc88fe1a2add59..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/RadioGroupJsonElement.php
+++ /dev/null
@@ -1,120 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-use TYPO3\CMS\Core\Utility\ArrayUtility;
-
-/**
- * JSON radiogroup
- */
-class RadioGroupJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\FieldsetJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-predefined-radiogroup';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [],
-        'legend' => [
-            'value' => ''
-        ],
-        'options' => [],
-        'various' => [
-            'name' => ''
-        ],
-        'validation' => []
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'class',
-        'dir',
-        'id',
-        'lang',
-        'style'
-    ];
-
-    /**
-     * Set all the parameters for this object
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     * @see \TYPO3\CMS\Form\Domain\Model\Json\FieldsetJsonElement::setParameters()
-     */
-    public function setParameters(array $parameters)
-    {
-        parent::setParameters($parameters);
-        $this->setOptions($parameters);
-        $this->setVarious($parameters);
-    }
-
-    /**
-     * Set the options for this object
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setOptions(array $parameters)
-    {
-        if (is_array($parameters)) {
-            $keys = ArrayUtility::filterAndSortByNumericKeys($parameters);
-            foreach ($keys as $key) {
-                $class = $parameters[$key];
-                if ((int)$key && strpos($key, '.') === false) {
-                    if (isset($parameters[$key . '.']) && $class === 'RADIO') {
-                        $childElementArguments = $parameters[$key . '.'];
-                        if (isset($childElementArguments['checked'])) {
-                            $childElementArguments['attributes']['selected'] = 'selected';
-                            unset($childElementArguments['checked']);
-                        }
-                        if (isset($childElementArguments['value'])) {
-                            $childElementArguments['attributes']['value'] = $childElementArguments['value'];
-                            unset($childElementArguments['value']);
-                        }
-                        if (isset($childElementArguments['label.'])) {
-                            $childElementArguments['text'] = $childElementArguments['label.']['value'];
-                            unset($childElementArguments['label.']);
-                        }
-                        $this->configuration['options'][] = $childElementArguments;
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Set the various properties for this object
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setVarious(array $parameters)
-    {
-        if (isset($parameters['name'])) {
-            $this->configuration['various']['name'] = $parameters['name'];
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/RadioJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/RadioJsonElement.php
deleted file mode 100644
index dec274e5d4729e0624abb5a535110c3cba20ab60..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/RadioJsonElement.php
+++ /dev/null
@@ -1,77 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON radio
- */
-class RadioJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-basic-radio';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [
-            'type' => 'radio'
-        ],
-        'filters' => [],
-        'label' => [
-            'value' => ''
-        ],
-        'layout' => 'back',
-        'validation' => []
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'accesskey',
-        'class',
-        'contenteditable',
-        'contextmenu',
-        'dir',
-        'draggable',
-        'dropzone',
-        'hidden',
-        'id',
-        'lang',
-        'spellcheck',
-        'style',
-        'tabindex',
-        'title',
-        'translate',
-        /* element specific attributes */
-        'autofocus',
-        'checked',
-        'disabled',
-        'name',
-        'readonly',
-        'required',
-        'type',
-        'value'
-    ];
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/ResetJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/ResetJsonElement.php
deleted file mode 100644
index 389f455b4fdd064b4c776f68ac3d8d231f645237..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/ResetJsonElement.php
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON reset
- */
-class ResetJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-basic-reset';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [
-            'type' => 'reset'
-        ],
-        'filters' => [],
-        'label' => [
-            'value' => ''
-        ],
-        'layout' => 'front',
-        'validation' => []
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'accesskey',
-        'class',
-        'contenteditable',
-        'contextmenu',
-        'dir',
-        'draggable',
-        'dropzone',
-        'hidden',
-        'id',
-        'lang',
-        'spellcheck',
-        'style',
-        'tabindex',
-        'title',
-        'translate',
-        /* element specific attributes */
-        'autofocus',
-        'disabled',
-        'name',
-        'type',
-        'value'
-    ];
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/SelectJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/SelectJsonElement.php
deleted file mode 100644
index 54b62f1f7c392574d40bbb96cc58db32ec83ac56..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/SelectJsonElement.php
+++ /dev/null
@@ -1,120 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-use TYPO3\CMS\Core\Utility\ArrayUtility;
-
-/**
- * JSON select
- */
-class SelectJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-basic-select';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [],
-        'filters' => [],
-        'label' => [
-            'value' => ''
-        ],
-        'layout' => 'front',
-        'options' => [],
-        'validation' => []
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'accesskey',
-        'class',
-        'contenteditable',
-        'contextmenu',
-        'dir',
-        'draggable',
-        'dropzone',
-        'hidden',
-        'id',
-        'lang',
-        'spellcheck',
-        'style',
-        'tabindex',
-        'title',
-        'translate',
-        /* element specific attributes */
-        'autofocus',
-        'disabled',
-        'multiple',
-        'name',
-        'required',
-        'size'
-    ];
-
-    protected $childElementsAllowed = false;
-
-    /**
-     * Set all the parameters for this object
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     * @see \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement::setParameters()
-     */
-    public function setParameters(array $parameters)
-    {
-        parent::setParameters($parameters);
-        $this->setOptions($parameters);
-    }
-
-    /**
-     * Set the options for this object
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setOptions(array $parameters)
-    {
-        if (is_array($parameters)) {
-            $keys = ArrayUtility::filterAndSortByNumericKeys($parameters);
-            foreach ($keys as $key) {
-                $class = $parameters[$key];
-                if ((int)$key && strpos($key, '.') === false) {
-                    if (isset($parameters[$key . '.']) && $class === 'OPTION') {
-                        $childElementArguments = $parameters[$key . '.'];
-                        if (isset($childElementArguments['selected'])) {
-                            $childElementArguments['attributes']['selected'] = $childElementArguments['selected'];
-                            unset($childElementArguments['selected']);
-                        }
-                        if (isset($childElementArguments['value'])) {
-                            $childElementArguments['attributes']['value'] = $childElementArguments['value'];
-                            unset($childElementArguments['value']);
-                        }
-                        $this->configuration['options'][] = $childElementArguments;
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/SubmitJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/SubmitJsonElement.php
deleted file mode 100644
index 514e405992844d0a13beb7cb2aaf51090d65ce17..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/SubmitJsonElement.php
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON submit
- */
-class SubmitJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-basic-submit';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [
-            'type' => 'submit'
-        ],
-        'filters' => [],
-        'label' => [
-            'value' => ''
-        ],
-        'layout' => 'front',
-        'validation' => []
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'accesskey',
-        'class',
-        'contenteditable',
-        'contextmenu',
-        'dir',
-        'draggable',
-        'dropzone',
-        'hidden',
-        'id',
-        'lang',
-        'spellcheck',
-        'style',
-        'tabindex',
-        'title',
-        'translate',
-        /* element specific attributes */
-        'autofocus',
-        'disabled',
-        'name',
-        'type',
-        'value'
-    ];
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/TextareaJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/TextareaJsonElement.php
deleted file mode 100644
index 4a0a8d30657ba5470a00b411fa4cdaab691e37a6..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/TextareaJsonElement.php
+++ /dev/null
@@ -1,97 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON textarea
- */
-class TextareaJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-basic-textarea';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [
-            'cols' => 40,
-            'rows' => 5
-        ],
-        'filters' => [],
-        'label' => [
-            'value' => ''
-        ],
-        'layout' => 'front',
-        'validation' => []
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'accesskey',
-        'class',
-        'contenteditable',
-        'contextmenu',
-        'dir',
-        'draggable',
-        'dropzone',
-        'hidden',
-        'id',
-        'lang',
-        'spellcheck',
-        'style',
-        'tabindex',
-        'title',
-        'translate',
-        /* element specific attributes */
-        'autofocus',
-        'cols',
-        'disabled',
-        'inputmode',
-        'maxlength',
-        'minlength',
-        'name',
-        'placeholder',
-        'readonly',
-        'required',
-        'rows',
-        'selectionDirection',
-        'selectionEnd',
-        'selectionStart',
-        'text',
-        'wrap'
-    ];
-
-    /**
-     * Set the attributes according to the allowed attributes of this element
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setAttributes(array $parameters)
-    {
-        parent::setAttributes($parameters);
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/TextblockJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/TextblockJsonElement.php
deleted file mode 100644
index 970a5d055bd05cd432ace8685ecbb2b1c9915ce0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/TextblockJsonElement.php
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON textblock
- */
-class TextblockJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-content-textblock';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [],
-        'various' => [
-            'text' => ''
-        ]
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'class',
-        'dir',
-        'id',
-        'lang',
-        'style',
-        'title'
-    ];
-
-    /**
-     * Set all the parameters for this object
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     * @see \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement::setParameters()
-     */
-    public function setParameters(array $parameters)
-    {
-        parent::setParameters($parameters);
-        $this->setVarious($parameters);
-    }
-
-    /**
-     * Set the various properties for the element
-     *
-     * For this element this is the headingsize and the value
-     *
-     * @param array $parameters Configuration array
-     * @return void
-     */
-    protected function setVarious(array $parameters)
-    {
-        if (isset($parameters['text'])) {
-            $this->configuration['various']['text'] = $parameters['text'];
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Json/TextlineJsonElement.php b/typo3/sysext/form/Classes/Domain/Model/Json/TextlineJsonElement.php
deleted file mode 100644
index f4ea76428c2e4c175f624b64200d5d3435d446be..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/Json/TextlineJsonElement.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model\Json;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * JSON textline
- */
-class TextlineJsonElement extends \TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement
-{
-    /**
-     * The ExtJS xtype of the element
-     *
-     * @var string
-     */
-    public $xtype = 'typo3-form-wizard-elements-basic-textline';
-
-    /**
-     * The configuration array for the xtype
-     *
-     * @var array
-     */
-    public $configuration = [
-        'attributes' => [
-            'type' => 'text'
-        ],
-        'filters' => [],
-        'label' => [
-            'value' => ''
-        ],
-        'layout' => 'front',
-        'validation' => []
-    ];
-
-    /**
-     * Allowed attributes for this object
-     *
-     * @var array
-     */
-    protected $allowedAttributes = [
-        'accesskey',
-        'class',
-        'contenteditable',
-        'contextmenu',
-        'dir',
-        'draggable',
-        'dropzone',
-        'hidden',
-        'id',
-        'lang',
-        'spellcheck',
-        'style',
-        'tabindex',
-        'title',
-        'translate',
-        /* element specific attributes */
-        'autocomplete',
-        'autofocus',
-        'disabled',
-        'inputmode',
-        'list',
-        'maxlength',
-        'minlength',
-        'name',
-        'pattern',
-        'placeholder',
-        'readonly',
-        'required',
-        'size',
-        'type',
-        'value'
-    ];
-}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Renderable/AbstractCompositeRenderable.php b/typo3/sysext/form/Classes/Domain/Model/Renderable/AbstractCompositeRenderable.php
new file mode 100644
index 0000000000000000000000000000000000000000..adda0931a113168023a797ec64c58676ba34fdb1
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/Renderable/AbstractCompositeRenderable.php
@@ -0,0 +1,210 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\Renderable;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Model\Exception\FormDefinitionConsistencyException;
+
+/**
+ * Convenience base class which implements common functionality for most
+ * classes which implement CompositeRenderableInterface, i.e. have **child renderable elements**.
+ *
+ * Scope: frontend
+ * **This class is NOT meant to be sub classed by developers.**
+ */
+abstract class AbstractCompositeRenderable extends AbstractRenderable implements CompositeRenderableInterface
+{
+
+    /**
+     * array of child renderables
+     *
+     * @var \TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface[]
+     */
+    protected $renderables = [];
+
+    /**
+     * Add a renderable to the list of child renderables.
+     *
+     * This function will be wrapped by the subclasses, f.e. with an "addPage"
+     * or "addElement" method with the correct type hint.
+     *
+     * @param RenderableInterface $renderable
+     * @return void
+     * @throws FormDefinitionConsistencyException
+     * @internal
+     */
+    protected function addRenderable(RenderableInterface $renderable)
+    {
+        if ($renderable->getParentRenderable() !== null) {
+            throw new FormDefinitionConsistencyException(sprintf('The renderable with identifier "%s" is already added to another element (element identifier: "%s").', $renderable->getIdentifier(), $renderable->getParentRenderable()->getIdentifier()), 1325665144);
+        }
+        $renderable->setIndex(count($this->renderables));
+        $renderable->setParentRenderable($this);
+        $this->renderables[] = $renderable;
+    }
+
+    /**
+     * Move $renderableToMove before $referenceRenderable
+     *
+     * This function will be wrapped by the subclasses, f.e. with an "movePageBefore"
+     * or "moveElementBefore" method with the correct type hint.
+     *
+     * @param RenderableInterface $renderableToMove
+     * @param RenderableInterface $referenceRenderable
+     * @return void
+     * @throws FormDefinitionConsistencyException
+     * @internal
+     */
+    protected function moveRenderableBefore(RenderableInterface $renderableToMove, RenderableInterface $referenceRenderable)
+    {
+        if ($renderableToMove->getParentRenderable() !== $referenceRenderable->getParentRenderable() || $renderableToMove->getParentRenderable() !== $this) {
+            throw new FormDefinitionConsistencyException('Moved renderables need to be part of the same parent element.', 1326089744);
+        }
+
+        $reorderedRenderables = [];
+        $i = 0;
+        foreach ($this->renderables as $renderable) {
+            if ($renderable === $renderableToMove) {
+                continue;
+            }
+
+            if ($renderable === $referenceRenderable) {
+                $reorderedRenderables[] = $renderableToMove;
+                $renderableToMove->setIndex($i);
+                $i++;
+            }
+            $reorderedRenderables[] = $renderable;
+            $renderable->setIndex($i);
+            $i++;
+        }
+        $this->renderables = $reorderedRenderables;
+    }
+
+    /**
+     * Move $renderableToMove after $referenceRenderable
+     *
+     * This function will be wrapped by the subclasses, f.e. with an "movePageAfter"
+     * or "moveElementAfter" method with the correct type hint.
+     *
+     * @param RenderableInterface $renderableToMove
+     * @param RenderableInterface $referenceRenderable
+     * @return void
+     * @throws FormDefinitionConsistencyException
+     * @internal
+     */
+    protected function moveRenderableAfter(RenderableInterface $renderableToMove, RenderableInterface $referenceRenderable)
+    {
+        if ($renderableToMove->getParentRenderable() !== $referenceRenderable->getParentRenderable() || $renderableToMove->getParentRenderable() !== $this) {
+            throw new FormDefinitionConsistencyException('Moved renderables need to be part of the same parent element.', 1477083145);
+        }
+
+        $reorderedRenderables = [];
+        $i = 0;
+        foreach ($this->renderables as $renderable) {
+            if ($renderable === $renderableToMove) {
+                continue;
+            }
+
+            $reorderedRenderables[] = $renderable;
+            $renderable->setIndex($i);
+            $i++;
+
+            if ($renderable === $referenceRenderable) {
+                $reorderedRenderables[] = $renderableToMove;
+                $renderableToMove->setIndex($i);
+                $i++;
+            }
+        }
+        $this->renderables = $reorderedRenderables;
+    }
+
+    /**
+     * Returns all RenderableInterface instances of this composite renderable recursively
+     *
+     * @return RenderableInterface[]
+     * @internal
+     */
+    public function getRenderablesRecursively(): array
+    {
+        $renderables = [];
+        foreach ($this->renderables as $renderable) {
+            $renderables[] = $renderable;
+            if ($renderable instanceof CompositeRenderableInterface) {
+                $renderables = array_merge($renderables, $renderable->getRenderablesRecursively());
+            }
+        }
+        return $renderables;
+    }
+
+    /**
+     * Remove a renderable from this renderable.
+     *
+     * This function will be wrapped by the subclasses, f.e. with an "removePage"
+     * or "removeElement" method with the correct type hint.
+     *
+     * @param RenderableInterface $renderableToRemove
+     * @return void
+     * @throws FormDefinitionConsistencyException
+     * @internal
+     */
+    protected function removeRenderable(RenderableInterface $renderableToRemove)
+    {
+        if ($renderableToRemove->getParentRenderable() !== $this) {
+            throw new FormDefinitionConsistencyException('The renderable to be removed must be part of the calling parent renderable.', 1326090127);
+        }
+
+        $updatedRenderables = [];
+        foreach ($this->renderables as $renderable) {
+            if ($renderable === $renderableToRemove) {
+                continue;
+            }
+
+            $updatedRenderables[] = $renderable;
+        }
+        $this->renderables = $updatedRenderables;
+
+        $renderableToRemove->onRemoveFromParentRenderable();
+    }
+
+    /**
+     * Register this element at the parent form, if there is a connection to the parent form.
+     *
+     * @return void
+     * @internal
+     */
+    public function registerInFormIfPossible()
+    {
+        parent::registerInFormIfPossible();
+        foreach ($this->renderables as $renderable) {
+            $renderable->registerInFormIfPossible();
+        }
+    }
+
+    /**
+     * This function is called after a renderable has been removed from its parent
+     * renderable.
+     * This just passes the event down to all child renderables of this composite renderable.
+     *
+     * @return void
+     * @internal
+     */
+    public function onRemoveFromParentRenderable()
+    {
+        foreach ($this->renderables as $renderable) {
+            $renderable->onRemoveFromParentRenderable();
+        }
+        parent::onRemoveFromParentRenderable();
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Renderable/AbstractRenderable.php b/typo3/sysext/form/Classes/Domain/Model/Renderable/AbstractRenderable.php
new file mode 100644
index 0000000000000000000000000000000000000000..9bfbb596e14155265a26e6ec8f9214cba132f922
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/Renderable/AbstractRenderable.php
@@ -0,0 +1,423 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\Renderable;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\ArrayUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface;
+use TYPO3\CMS\Form\Domain\Model\Exception\FormDefinitionConsistencyException;
+use TYPO3\CMS\Form\Domain\Model\Exception\ValidatorPresetNotFoundException;
+use TYPO3\CMS\Form\Domain\Model\FormDefinition;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+use TYPO3\CMS\Form\Utility\ArrayUtility as FormArrayUtility;
+
+/**
+ * Convenience base class which implements common functionality for most
+ * classes which implement RenderableInterface.
+ *
+ * Scope: frontend
+ * **This class is NOT meant to be sub classed by developers.**
+ * @internal
+ */
+abstract class AbstractRenderable implements RenderableInterface
+{
+
+    /**
+     * Abstract "type" of this Renderable. Is used during the rendering process
+     * to determine the template file or the View PHP class being used to render
+     * the particular element.
+     *
+     * @var string
+     */
+    protected $type;
+
+    /**
+     * The identifier of this renderable
+     *
+     * @var string
+     */
+    protected $identifier;
+
+    /**
+     * The parent renderable
+     *
+     * @var CompositeRenderableInterface
+     */
+    protected $parentRenderable;
+
+    /**
+     * The label of this renderable
+     *
+     * @var string
+     */
+    protected $label = '';
+
+    /**
+     * associative array of rendering options
+     *
+     * @var array
+     */
+    protected $renderingOptions = [];
+
+    /**
+     * Renderer class name to be used for this renderable.
+     *
+     * Is only set if a specific renderer should be used for this renderable,
+     * if it is NULL the caller needs to determine the renderer or take care
+     * of the rendering itself.
+     *
+     * @var string
+     */
+    protected $rendererClassName = null;
+
+    /**
+     * The position of this renderable inside the parent renderable.
+     *
+     * @var int
+     */
+    protected $index = 0;
+
+    /**
+     * Get the type of the renderable
+     *
+     * @return string
+     * @api
+     */
+    public function getType(): string
+    {
+        return $this->type;
+    }
+
+    /**
+     * Get the identifier of the element
+     *
+     * @return string
+     * @api
+     */
+    public function getIdentifier(): string
+    {
+        return $this->identifier;
+    }
+
+    /**
+     * Set multiple properties of this object at once.
+     * Every property which has a corresponding set* method can be set using
+     * the passed $options array.
+     *
+     * @param array $options
+     * @return void
+     * @api
+     */
+    public function setOptions(array $options)
+    {
+        if (isset($options['label'])) {
+            $this->setLabel($options['label']);
+        }
+
+        if (isset($options['defaultValue'])) {
+            $this->setDefaultValue($options['defaultValue']);
+        }
+
+        if (isset($options['properties'])) {
+            foreach ($options['properties'] as $key => $value) {
+                $this->setProperty($key, $value);
+            }
+        }
+
+        if (isset($options['rendererClassName'])) {
+            $this->setRendererClassName($options['rendererClassName']);
+        }
+
+        if (isset($options['renderingOptions'])) {
+            foreach ($options['renderingOptions'] as $key => $value) {
+                if (is_array($value)) {
+                    $currentValue = isset($this->getRenderingOptions()[$key]) ? $this->getRenderingOptions()[$key] : [];
+                    ArrayUtility::mergeRecursiveWithOverrule($currentValue, $value);
+                    $this->setRenderingOption($key, $currentValue);
+                } else {
+                    $this->setRenderingOption($key, $value);
+                }
+            }
+        }
+
+        if (isset($options['validators'])) {
+            foreach ($options['validators'] as $validatorConfiguration) {
+                $this->createValidator($validatorConfiguration['identifier'], isset($validatorConfiguration['options']) ? $validatorConfiguration['options'] : []);
+            }
+        }
+
+        FormArrayUtility::assertAllArrayKeysAreValid($options, ['label', 'defaultValue', 'properties', 'rendererClassName', 'renderingOptions', 'validators', 'formEditor']);
+    }
+
+    /**
+     * Create a validator for the element
+     *
+     * @param string $validatorIdentifier
+     * @param array $options
+     * @return mixed
+     * @throws ValidatorPresetNotFoundException
+     * @api
+     */
+    public function createValidator(string $validatorIdentifier, array $options = [])
+    {
+        $validatorsDefinition = $this->getRootForm()->getValidatorsDefinition();
+        if (isset($validatorsDefinition[$validatorIdentifier]) && is_array($validatorsDefinition[$validatorIdentifier]) && isset($validatorsDefinition[$validatorIdentifier]['implementationClassName'])) {
+            $implementationClassName = $validatorsDefinition[$validatorIdentifier]['implementationClassName'];
+            $defaultOptions = isset($validatorsDefinition[$validatorIdentifier]['options']) ? $validatorsDefinition[$validatorIdentifier]['options'] : [];
+
+            ArrayUtility::mergeRecursiveWithOverrule($defaultOptions, $options);
+
+            $validator = GeneralUtility::makeInstance(ObjectManager::class)
+                ->get($implementationClassName, $defaultOptions);
+            $this->addValidator($validator);
+            return $validator;
+        } else {
+            throw new ValidatorPresetNotFoundException('The validator preset identified by "' . $validatorIdentifier . '" could not be found, or the implementationClassName was not specified.', 1328710202);
+        }
+    }
+
+    /**
+     * Add a validator to the element
+     *
+     * @param ValidatorInterface $validator
+     * @return void
+     * @api
+     */
+    public function addValidator(ValidatorInterface $validator)
+    {
+        $formDefinition = $this->getRootForm();
+        $formDefinition->getProcessingRule($this->getIdentifier())->addValidator($validator);
+    }
+
+    /**
+     * Get all validators on the element
+     *
+     * @return \SplObjectStorage
+     * @internal
+     */
+    public function getValidators(): \SplObjectStorage
+    {
+        $formDefinition = $this->getRootForm();
+        return $formDefinition->getProcessingRule($this->getIdentifier())->getValidators();
+    }
+
+    /**
+     * Set the datatype
+     *
+     * @param string $dataType
+     * @return void
+     * @api
+     */
+    public function setDataType(string $dataType)
+    {
+        $formDefinition = $this->getRootForm();
+        $formDefinition->getProcessingRule($this->getIdentifier())->setDataType($dataType);
+    }
+
+    /**
+     * Set the renderer class name
+     *
+     * @param string $rendererClassName
+     * @return void
+     * @api
+     */
+    public function setRendererClassName(string $rendererClassName)
+    {
+        $this->rendererClassName = $rendererClassName;
+    }
+
+    /**
+     * Get the classname of the renderer
+     *
+     * @return null|string
+     * @api
+     */
+    public function getRendererClassName()
+    {
+        return $this->rendererClassName;
+    }
+
+    /**
+     * Get all rendering options
+     *
+     * @return array
+     * @api
+     */
+    public function getRenderingOptions(): array
+    {
+        return $this->renderingOptions;
+    }
+
+    /**
+     * Set the rendering option $key to $value.
+     *
+     * @param string $key
+     * @param mixed $value
+     * @return mixed
+     * @api
+     */
+    public function setRenderingOption(string $key, $value)
+    {
+        $this->renderingOptions[$key] = $value;
+    }
+
+    /**
+     * Get the parent renderable
+     *
+     * @return null|CompositeRenderableInterface
+     * @return void
+     * @api
+     */
+    public function getParentRenderable()
+    {
+        return $this->parentRenderable;
+    }
+
+    /**
+     * Set the parent renderable
+     *
+     * @param CompositeRenderableInterface $parentRenderable
+     * @return void
+     * @api
+     */
+    public function setParentRenderable(CompositeRenderableInterface $parentRenderable)
+    {
+        $this->parentRenderable = $parentRenderable;
+        $this->registerInFormIfPossible();
+    }
+
+    /**
+     * Get the root form this element belongs to
+     *
+     * @return FormDefinition
+     * @throws FormDefinitionConsistencyException
+     * @api
+     */
+    public function getRootForm(): FormDefinition
+    {
+        $rootRenderable = $this->parentRenderable;
+        while ($rootRenderable !== null && !($rootRenderable instanceof FormDefinition)) {
+            $rootRenderable = $rootRenderable->getParentRenderable();
+        }
+        if ($rootRenderable === null) {
+            throw new FormDefinitionConsistencyException(sprintf('The form element "%s" is not attached to a parent form.', $this->identifier), 1326803398);
+        }
+
+        return $rootRenderable;
+    }
+
+    /**
+     * Register this element at the parent form, if there is a connection to the parent form.
+     *
+     * @return void
+     * @internal
+     */
+    public function registerInFormIfPossible()
+    {
+        try {
+            $rootForm = $this->getRootForm();
+            $rootForm->registerRenderable($this);
+        } catch (FormDefinitionConsistencyException $exception) {
+        }
+    }
+
+    /**
+     * Triggered when the renderable is removed from it's parent
+     *
+     * @return void
+     * @internal
+     */
+    public function onRemoveFromParentRenderable()
+    {
+        try {
+            $rootForm = $this->getRootForm();
+            $rootForm->unregisterRenderable($this);
+        } catch (FormDefinitionConsistencyException $exception) {
+        }
+        $this->parentRenderable = null;
+    }
+
+    /**
+     * Get the index of the renderable
+     *
+     * @return int
+     * @internal
+     */
+    public function getIndex(): int
+    {
+        return $this->index;
+    }
+
+    /**
+     * Set the index of the renderable
+     *
+     * @param int $index
+     * @return void
+     * @internal
+     */
+    public function setIndex(int $index)
+    {
+        $this->index = $index;
+    }
+
+    /**
+     * Get the label of the renderable
+     *
+     * @return string
+     * @api
+     */
+    public function getLabel(): string
+    {
+        return $this->label;
+    }
+
+    /**
+     * Set the label which shall be displayed next to the form element
+     *
+     * @param string $label
+     * @return void
+     * @api
+     */
+    public function setLabel(string $label)
+    {
+        $this->label = $label;
+    }
+
+    /**
+     * Override this method in your custom Renderable if needed
+     *
+     * @param FormRuntime $formRuntime
+     * @return void
+     * @api
+     */
+    public function beforeRendering(FormRuntime $formRuntime)
+    {
+    }
+
+    /**
+     * This is a callback that is invoked by the Form Factory after the whole form has been built.
+     * It can be used to add new form elements as children for complex form elements.
+     *
+     * Override this method in your custom Renderable if needed.
+     *
+     * @return void
+     * @api
+     */
+    public function onBuildingFinished()
+    {
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Renderable/CompositeRenderableInterface.php b/typo3/sysext/form/Classes/Domain/Model/Renderable/CompositeRenderableInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..4e15db0f0344f4b65974b67626f52cfdf53afc9a
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/Renderable/CompositeRenderableInterface.php
@@ -0,0 +1,35 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\Renderable;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Interface which all Form Parts must adhere to **when they have sub elements**.
+ * This includes especially "FormDefinition" and "Page".
+ *
+ * Scope: frontend
+ * **This class is NOT meant to be sub classed by developers.**
+ */
+interface CompositeRenderableInterface extends RenderableInterface
+{
+
+    /**
+     * Returns all RenderableInterface instances of this composite renderable recursively
+     *
+     * @return \TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface[]
+     * @internal
+     */
+    public function getRenderablesRecursively(): array;
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Renderable/RenderableInterface.php b/typo3/sysext/form/Classes/Domain/Model/Renderable/RenderableInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..f473dfad8fa0939155106c26d9801d6b2f83806d
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/Renderable/RenderableInterface.php
@@ -0,0 +1,92 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\Renderable;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Base interface which all Form Parts except the FormDefinition must adhere
+ * to (i.e. all elements which are NOT the root of a Form).
+ *
+ * Scope: frontend
+ * **This class is NOT meant to be sub classed by developers.**
+ */
+interface RenderableInterface extends RootRenderableInterface
+{
+
+    /**
+     * Return the parent renderable
+     *
+     * @return null|CompositeRenderableInterface the parent renderable
+     * @internal
+     */
+    public function getParentRenderable();
+
+    /**
+     * Set the new parent renderable. You should not call this directly;
+     * it is automatically called by addRenderable.
+     *
+     * This method should also register itself at the parent form, if possible.
+     *
+     * @param CompositeRenderableInterface $renderable
+     * @return void
+     * @internal
+     */
+    public function setParentRenderable(CompositeRenderableInterface $renderable);
+
+    /**
+     * Set the index of this renderable inside the parent renderable
+     *
+     * @param int $index
+     * @return void
+     * @internal
+     */
+    public function setIndex(int $index);
+
+    /**
+     * Get the index inside the parent renderable
+     *
+     * @return int
+     * @api
+     */
+    public function getIndex(): int;
+
+    /**
+     * This function is called after a renderable has been removed from its parent
+     * renderable. The function should make sure to clean up the internal state,
+     * like reseting $this->parentRenderable or deregistering the renderable
+     * at the form.
+     *
+     * @return void
+     * @internal
+     */
+    public function onRemoveFromParentRenderable();
+
+    /**
+     * This is a callback that is invoked by the Form Factory after the whole form has been built.
+     * It can be used to add new form elements as children for complex form elements.
+     *
+     * @return void
+     * @api
+     */
+    public function onBuildingFinished();
+
+    /**
+     * Register this element at the parent form, if there is a connection to the parent form.
+     *
+     * @return void
+     * @internal
+     */
+    public function registerInFormIfPossible();
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/Renderable/RootRenderableInterface.php b/typo3/sysext/form/Classes/Domain/Model/Renderable/RootRenderableInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..e0ece97b35970e0f9a3e8a81933822858f2142d6
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Model/Renderable/RootRenderableInterface.php
@@ -0,0 +1,86 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Model\Renderable;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+
+/**
+ * Base interface which all parts of a form must adhere to.
+ *
+ * Scope: frontend
+ * **This class is NOT meant to be sub classed by developers.**
+ */
+interface RootRenderableInterface
+{
+
+    /**
+     * Abstract "type" of this Renderable. Is used during the rendering process
+     * to determine the template file or the View PHP class being used to render
+     * the particular element.
+     *
+     * @return string
+     * @api
+     */
+    public function getType(): string;
+
+    /**
+     * The identifier of this renderable
+     *
+     * @return string
+     * @api
+     */
+    public function getIdentifier(): string;
+
+    /**
+     * Get the label which shall be displayed next to the form element
+     *
+     * @return string
+     * @api
+     */
+    public function getLabel(): string;
+
+    /**
+     * This is a callback that is invoked by the Renderer before the corresponding element is rendered.
+     * Use this to access previously submitted values and/or modify the $formRuntime before an element
+     * is outputted to the browser.
+     *
+     * @param FormRuntime $formRuntime
+     * @return void
+     * @api
+     */
+    public function beforeRendering(FormRuntime $formRuntime);
+
+    /**
+     * Get the renderer class name to be used to display this renderable;
+     * must implement RendererInterface
+     *
+     * Is only set if a specific renderer should be used for this renderable,
+     * if it is NULL the caller needs to determine the renderer or take care
+     * of the renderer itself.
+     *
+     * @return null|string the renderer class name
+     * @api
+     */
+    public function getRendererClassName();
+
+    /**
+     * Get all rendering options
+     *
+     * @return array associative array of rendering options
+     * @api
+     */
+    public function getRenderingOptions(): array;
+}
diff --git a/typo3/sysext/form/Classes/Domain/Model/ValidationElement.php b/typo3/sysext/form/Classes/Domain/Model/ValidationElement.php
deleted file mode 100644
index 15812fc2c8c1fdfc860586ded8b73e2e99b74a73..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Model/ValidationElement.php
+++ /dev/null
@@ -1,89 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Model;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
-
-/**
- * The ValidationElement Domain Model represents the low-level
- * view on the user submitted data in a flat hierarchy.
- */
-class ValidationElement extends AbstractEntity
-{
-    /**
-     * This array holds all the field from the request
-     *
-     * @var array
-     */
-    protected $incomingFields;
-
-    /**
-     * Return a array with all the fields from the request
-     *
-     * @return array
-     */
-    public function getIncomingFields()
-    {
-        return $this->incomingFields;
-    }
-
-    /**
-     * Sets a array with all the fields from the request
-     *
-     * @param array $incomingFields
-     * @return void
-     */
-    public function setIncomingFields($incomingFields = [])
-    {
-        $this->incomingFields = $incomingFields;
-    }
-
-    /**
-     * Get a single fields from the request
-     *
-     * @param string $key
-     * @return mixed
-     */
-    public function getIncomingField($key = '')
-    {
-        return $this->incomingFields[$key];
-    }
-
-    /**
-     * Set a single fields from the request
-     *
-     * @param string $key
-     * @param mixed $value
-     * @return array
-     */
-    public function setIncomingField($key = '', $value = null)
-    {
-        $this->incomingFields[$key] = $value;
-    }
-
-    /**
-     * Determines whether a field is part of the incoming fields.
-     *
-     * @param string $key The key of the field to be looked up
-     * @return bool
-     */
-    public function hasIncomingField($key)
-    {
-        return
-            isset($this->incomingFields[$key])
-            || array_key_exists($key, $this->incomingFields)
-        ;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Property/TypeConverter/ArrayToValidationElementConverter.php b/typo3/sysext/form/Classes/Domain/Property/TypeConverter/ArrayToValidationElementConverter.php
deleted file mode 100644
index f5e0b1824b9cadb8ec4a127edc8cec22cde0c7c3..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Property/TypeConverter/ArrayToValidationElementConverter.php
+++ /dev/null
@@ -1,124 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Property\TypeConverter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface;
-use TYPO3\CMS\Extbase\Property\TypeConverter\AbstractTypeConverter;
-use TYPO3\CMS\Form\Domain\Model\ValidationElement;
-
-/**
- * The form wizard controller
- */
-class ArrayToValidationElementConverter extends AbstractTypeConverter
-{
-    /**
-     * @var array<string>
-     */
-    protected $sourceTypes = ['array'];
-
-    /**
-     * @var string
-     */
-    protected $targetType = 'TYPO3\\CMS\\Form\\Domain\\Model\\ValidationElement';
-
-    /**
-     * @var int
-     */
-    protected $priority = 1;
-
-    /**
-     * We can only convert empty strings to array or array to array.
-     *
-     * @param mixed $source
-     * @param string $targetType
-     * @return bool
-     */
-    public function canConvertFrom($source, $targetType)
-    {
-        return is_array($source);
-    }
-
-    /**
-     * Convert the incoming array to a ValidationElement
-     *
-     * @param array $source
-     * @param string $targetType
-     * @param array $convertedChildProperties
-     * @param PropertyMappingConfigurationInterface $configuration
-     * @return ValidationElement
-     * @api
-     */
-    public function convertFrom($source, $targetType, array $convertedChildProperties = [], PropertyMappingConfigurationInterface $configuration = null)
-    {
-        /** @var ValidationElement $validationElement */
-        $validationElement = GeneralUtility::makeInstance(ValidationElement::class);
-        if (is_array($source)) {
-            /**
-             * Find uploaded files.
-             *
-             * Extbase has already mapped the $_FILES data into the request
-             * @see TYPO3\CMS\Extbase\Mvc\Web\Request::build()
-             * If a $_FILES array is found in the request data ($source),
-             * set the file mime type with
-             * \TYPO3\CMS\Core\Type\File\FileInfo
-             * and write the data back into $source.
-             */
-            foreach ($source as $propertyName => $value) {
-                if (is_array($value)) {
-                    $uploadedFiles = [];
-                    if (
-                        isset($value['name'])
-                        && isset($value['type'])
-                        && isset($value['tmp_name'])
-                        && isset($value['size'])
-                    ) {
-                        // if single file upload - cast to array
-                        $uploadedFiles[] = $value;
-                    } elseif (
-                        isset($value[0]['name'])
-                        && isset($value[0]['type'])
-                        && isset($value[0]['tmp_name'])
-                        && isset($value[0]['size'])
-                    ) {
-                        // multi file upload
-                        $uploadedFiles = $value;
-                    }
-
-                    if (!empty($uploadedFiles)) {
-                        foreach ($uploadedFiles as $key => &$file) {
-                            if (
-                                $file['name'] === ''
-                                && $file['type'] === ''
-                                && $file['tmp_name'] === ''
-                                && $file['size'] === 0
-                            ) {
-                                unset($uploadedFiles[$key]);
-                                continue;
-                            }
-                            $fileInfo = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Type\File\FileInfo::class, $file['tmp_name']);
-                            $file['type'] = $fileInfo->getMimeType();
-                            $file['name'] = htmlspecialchars($file['name']);
-                        }
-                        $source[$propertyName] = $uploadedFiles;
-                    }
-                }
-            }
-            $validationElement->setIncomingFields($source);
-        }
-
-        return $validationElement;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Renderer/AbstractElementRenderer.php b/typo3/sysext/form/Classes/Domain/Renderer/AbstractElementRenderer.php
new file mode 100644
index 0000000000000000000000000000000000000000..ba766239fc43cd110a6de444076c358e2767cdf0
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Renderer/AbstractElementRenderer.php
@@ -0,0 +1,73 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Renderer;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+
+/**
+ * Abstract renderer which can be used as base class for custom renderers.
+ *
+ * Scope: frontend
+ * **This class is meant to be sub classed by developers**.
+ * @api
+ */
+abstract class AbstractElementRenderer implements RendererInterface
+{
+
+    /**
+     * The assigned controller context which might be needed by the renderer.
+     *
+     * @var \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext
+     * @api
+     */
+    protected $controllerContext;
+
+    /**
+     * @var \TYPO3\CMS\Form\Domain\Runtime\FormRuntime
+     * @api
+     */
+    protected $formRuntime;
+
+    /**
+     * Set the controller context which should be used
+     *
+     * @param \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext $controllerContext
+     * @api
+     */
+    public function setControllerContext(\TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext $controllerContext)
+    {
+        $this->controllerContext = $controllerContext;
+    }
+
+    /**
+     * @param FormRuntime $formRuntime
+     * @return void
+     * @api
+     */
+    public function setFormRuntime(FormRuntime $formRuntime)
+    {
+        $this->formRuntime = $formRuntime;
+    }
+
+    /**
+     * @return FormRuntime
+     * @api
+     */
+    public function getFormRuntime(): FormRuntime
+    {
+        return $this->formRuntime;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Renderer/FluidFormRenderer.php b/typo3/sysext/form/Classes/Domain/Renderer/FluidFormRenderer.php
new file mode 100644
index 0000000000000000000000000000000000000000..0f2311d6696664e6220dc22254fa62cbb312a5de
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Renderer/FluidFormRenderer.php
@@ -0,0 +1,54 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Renderer;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface;
+use TYPO3\CMS\Form\Mvc\View\FormView;
+
+/**
+ * A renderer which render all renderables within the $formRuntime.
+ * All the work is done within FormView::class.
+ * This is just a proxy class to make the rendering process more clear.
+ * See the documentation within FormView::class for additional information.
+ *
+ * Scope: frontend
+ * **This class is NOT meant to be sub classed by developers.**
+ * @internal
+ */
+class FluidFormRenderer extends AbstractElementRenderer implements RendererInterface
+{
+
+    /**
+     * Initialize the FormView::class and render the this->formRuntime.
+     * This method is expected to invoke the beforeRendering() callback
+     * on each $renderable. This is done within FormView::class.
+     *
+     * @param RootRenderableInterface $renderable
+     * @return string the rendered $formRuntime
+     * @internal
+     */
+    public function render(RootRenderableInterface $renderable): string
+    {
+        $formView = GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(FormView::class);
+
+        $formView->setFormRuntime($this->formRuntime);
+        $formView->setControllerContext($this->controllerContext);
+        return $formView->renderRenderable($renderable);
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Renderer/RendererInterface.php b/typo3/sysext/form/Classes/Domain/Renderer/RendererInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..e67416ee429794c5fba272e8980ba095d34bc791
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Renderer/RendererInterface.php
@@ -0,0 +1,62 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Renderer;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+
+/**
+ * Base interface for Renderers. A Renderer is used to render a renderable.
+ *
+ * Scope: frontend
+ * **This interface is meant to be implemented by developers, although often you
+ * will subclass AbstractElementRenderer** ({@link AbstractElementRenderer}).
+ */
+interface RendererInterface
+{
+
+    /**
+     * Set the controller context which should be used
+     *
+     * @param ControllerContext $controllerContext
+     * @api
+     */
+    public function setControllerContext(ControllerContext $controllerContext);
+
+    /**
+     * Note: This method is expected to invoke the beforeRendering() callback
+     * on each $renderable
+     *
+     * @param RootRenderableInterface $renderable
+     * @return string the rendered $formRuntime
+     * @api
+     */
+    public function render(RootRenderableInterface $renderable): string;
+
+    /**
+     * @param FormRuntime $formRuntime
+     * @return void
+     * @api
+     */
+    public function setFormRuntime(FormRuntime $formRuntime);
+
+    /**
+     * @return FormRuntime
+     * @api
+     */
+    public function getFormRuntime(): FormRuntime;
+}
diff --git a/typo3/sysext/form/Classes/Domain/Renderer/UnknownFormElementRenderer.php b/typo3/sysext/form/Classes/Domain/Renderer/UnknownFormElementRenderer.php
new file mode 100644
index 0000000000000000000000000000000000000000..4dfefee55a4d9c63e7f340f5a82e4144d5698856
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Renderer/UnknownFormElementRenderer.php
@@ -0,0 +1,72 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Renderer;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Exception\TypeDefinitionNotFoundException;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface;
+
+/**
+ * Renderer for unknown Form Elements
+ * This is used to render Form Elements without definition depending on the context:
+ * In "preview mode" (e.g. inside the FormEditor) a div with an error message is rendered
+ * If previewMode is FALSE this will return an empty string if the rendering Option "skipUnknownElements" is TRUE for
+ * the form, or throw an Exception otherwise.
+ *
+ * Scope: frontend
+ */
+class UnknownFormElementRenderer extends AbstractElementRenderer
+{
+
+    /**
+     * This renders the given $renderable depending on the context:
+     * In preview Mode this returns an error message. Otherwise this throws an exception or returns an empty string
+     * depending on the "skipUnknownElements" rendering option
+     *
+     * @param RootRenderableInterface $renderable
+     * @return string the rendered $renderable
+     * @throws TypeDefinitionNotFoundException
+     * @internal
+     */
+    public function render(RootRenderableInterface $renderable): string
+    {
+        $renderingOptions = $this->formRuntime->getRenderingOptions();
+        $previewMode = isset($renderingOptions['previewMode']) && $renderingOptions['previewMode'] === true;
+        if ($previewMode) {
+            return sprintf('<div class="t3-form-unknown-element" data-element-identifier-path="%s"><em>Unknown Form Element "%s"</em></div>', htmlspecialchars($this->getRenderablePath($renderable)), htmlspecialchars($renderable->getType()));
+        }
+        $skipUnknownElements = isset($renderingOptions['skipUnknownElements']) && $renderingOptions['skipUnknownElements'] === true;
+        if (!$skipUnknownElements) {
+            throw new TypeDefinitionNotFoundException(sprintf('Type "%s" not found. Probably some configuration is missing.', $renderable->getType()), 1382364019);
+        }
+        return '';
+    }
+
+    /**
+     * Returns the path of a $renderable in the format <formIdentifier>/<sectionIdentifier>/<sectionIdentifier>/.../<elementIdentifier>
+     *
+     * @param RootRenderableInterface $renderable
+     * @return string
+     * @internal
+     */
+    protected function getRenderablePath(RootRenderableInterface $renderable): string
+    {
+        $path = $renderable->getIdentifier();
+        while ($renderable = $renderable->getParentRenderable()) {
+            $path = $renderable->getIdentifier() . '/' . $path;
+        }
+        return $path;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Repository/ContentRepository.php b/typo3/sysext/form/Classes/Domain/Repository/ContentRepository.php
deleted file mode 100644
index ee488067f5292b5ec011fdb41941f8a2388d5be6..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Repository/ContentRepository.php
+++ /dev/null
@@ -1,129 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Repository;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Form\Domain\Factory\JsonToTypoScript;
-use TYPO3\CMS\Form\Domain\Model\Content;
-use TYPO3\CMS\Form\Utility\TypoScriptToJsonConverter;
-
-/**
- * Repository for \TYPO3\CMS\Form\Domain\Model\Content
- */
-class ContentRepository
-{
-    /**
-     * Get the referenced record from the database
-     *
-     * Using the GET or POST variable 'P'
-     *
-     * @param null|int $recordId
-     * @param null|string $table
-     * @return bool|Content if found, FALSE if not
-     */
-    public function getRecord($recordId = null, $table = null)
-    {
-        $record = false;
-        $getPostVariables = GeneralUtility::_GP('P');
-        if (!$table) {
-            $table = 'tt_content';
-        }
-
-        if (!$recordId) {
-            $recordId = (int)$getPostVariables['uid'];
-        }
-
-        if ((int)$recordId === 0) {
-            /** @var $typoScriptParser TypoScriptParser */
-            $typoScriptParser = GeneralUtility::makeInstance(TypoScriptParser::class);
-            $typoScriptParser->parse('');
-            /** @var $record Content */
-            $record = GeneralUtility::makeInstance(Content::class);
-            $record->setUid(0);
-            $record->setPageId(0);
-            $record->setTyposcript($typoScriptParser->setup);
-            $record->setBodytext('');
-
-            return $record;
-        }
-
-        $row = BackendUtility::getRecord($table, (int)$recordId);
-        if (is_array($row)) {
-            // strip off the leading "[Translate to XY]" text after localizing the original record
-            $languageField = $GLOBALS['TCA']['tt_content']['ctrl']['languageField'];
-            $transOrigPointerField = $GLOBALS['TCA']['tt_content']['ctrl']['transOrigPointerField'];
-            if ($row[$languageField] > 0 && $row[$transOrigPointerField] > 0) {
-                $bodytext = preg_replace('/^\[.*?\] /', '', $row['bodytext'], 1);
-            } else {
-                $bodytext = $row['bodytext'];
-            }
-
-            /** @var $typoScriptParser TypoScriptParser */
-            $typoScriptParser = GeneralUtility::makeInstance(TypoScriptParser::class);
-            $typoScriptParser->parse($bodytext);
-            /** @var $record Content */
-            $record = GeneralUtility::makeInstance(Content::class);
-            $record->setUid($row['uid']);
-            $record->setPageId($row['pid']);
-            $record->setTyposcript($typoScriptParser->setup);
-            $record->setBodytext($bodytext);
-        }
-        return $record;
-    }
-
-    /**
-     * Check if the referenced record exists
-     *
-     * @return bool TRUE if record exists, FALSE if not
-     */
-    public function hasRecord()
-    {
-        return $this->getRecord() !== false;
-    }
-
-    /**
-     * Convert the incoming data of the FORM wizard
-     *
-     * @return string $typoscript after conversion
-     */
-    public function save()
-    {
-        $json = GeneralUtility::_GP('configuration');
-        /** @var $converter JsonToTypoScript */
-        $converter = GeneralUtility::makeInstance(JsonToTypoScript::class);
-        $typoscript = $converter->convert($json);
-        return $typoscript;
-    }
-
-    /**
-     * Read and convert the content record to JSON
-     *
-     * @return string The JSON object if record exists, FALSE if not
-     */
-    public function getRecordAsJson()
-    {
-        $json = false;
-        $record = $this->getRecord();
-        if ($record) {
-            $typoscript = $record->getTyposcript();
-            /** @var $converter TypoScriptToJsonConverter */
-            $converter = GeneralUtility::makeInstance(TypoScriptToJsonConverter::class);
-            $json = $converter->convert($typoscript);
-        }
-        return $json;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Repository/TypoScriptRepository.php b/typo3/sysext/form/Classes/Domain/Repository/TypoScriptRepository.php
deleted file mode 100644
index 88964381e5f5a7fcb89f624e45bf80c08e4ad91d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Repository/TypoScriptRepository.php
+++ /dev/null
@@ -1,223 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Repository;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\SingletonInterface;
-use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-/**
- * Provide the TypoScript data-source
- */
-class TypoScriptRepository implements SingletonInterface
-{
-    /**
-     * @var array
-     */
-    protected $modelDefinitionTypoScript = [];
-
-    /**
-     * @var array
-     */
-    protected $registeredElementTypes = [];
-
-    /**
-     * @var \TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser
-     */
-    protected $typoScriptParser;
-
-    /**
-     * The constructor
-     */
-    public function __construct()
-    {
-        $this->typoScriptParser = GeneralUtility::makeInstance(TypoScriptParser::class);
-        $this->modelDefinitionTypoScript = $this->resolveTypoScriptReferences(
-            $GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_form.']
-        );
-        $this->setRegisteredElementTypes();
-    }
-
-    /**
-     * Get all registered form elements
-     *
-     * @return array
-     */
-    public function getRegisteredElementTypes()
-    {
-        return $this->registeredElementTypes;
-    }
-
-    /**
-     * Set all registered form elements
-     *
-     * @param array $registeredElementTypes
-     * @return void
-     * @throws \InvalidArgumentException
-     */
-    public function setRegisteredElementTypes(array $registeredElementTypes = [])
-    {
-        if (!empty($registeredElementTypes)) {
-            $this->registeredElementTypes = $registeredElementTypes;
-        } else {
-            if (!isset($this->modelDefinitionTypoScript['settings.']['registeredElements.'])) {
-                throw new \InvalidArgumentException('There are no registeredElements available.', 1441791615);
-            }
-            $registeredElements = $this->modelDefinitionTypoScript['settings.']['registeredElements.'];
-            foreach ($registeredElements as $registeredElementKey => $value) {
-                $registeredElementKey = rtrim($registeredElementKey, '.');
-                $this->registeredElementTypes[] = $registeredElementKey;
-            }
-        }
-    }
-
-    /**
-     * Get the html attributes defined by the model
-     * with their default values
-     *
-     * @param string $elementType
-     * @return array
-     */
-    public function getModelDefinedHtmlAttributes($elementType = '')
-    {
-        if ($elementType == '') {
-            return [];
-        }
-        $htmlAttributes = $this->getModelConfigurationByScope($elementType, 'htmlAttributes.');
-        if (is_array($htmlAttributes)) {
-            $htmlAttributes = array_fill_keys($htmlAttributes, null);
-        } else {
-            $htmlAttributes = [];
-        }
-        $defaultHtmlAttributeValues = $this->getModelConfigurationByScope($elementType, 'defaultHtmlAttributeValues.');
-        if (is_array($defaultHtmlAttributeValues)) {
-            foreach ($defaultHtmlAttributeValues as $defaultHtmlAttributeKey => $defaultHtmlAttributeValue) {
-                $htmlAttributes[$defaultHtmlAttributeKey] = $defaultHtmlAttributeValue;
-            }
-        } elseif (!is_array($htmlAttributes)) {
-            $htmlAttributes = [];
-        }
-        return $htmlAttributes;
-    }
-
-    /**
-     * Get the default fluid template for a element.
-     *
-     * @param string $elementType
-     * @param string $partialType
-     * @return string
-     */
-    public function getDefaultFluidTemplate($elementType, $partialType = 'partialPath')
-    {
-        $partialPath = $this->getModelConfigurationByScope($elementType, $partialType);
-        if ($partialPath) {
-            return $partialPath;
-        }
-        return '';
-    }
-
-    /**
-     * Get the model definition from TypoScript for a specific scope.
-     *
-     * @param string $elementType
-     * @param string $scope
-     * @return mixed
-     */
-    public function getModelConfigurationByScope($elementType, $scope)
-    {
-        if (isset($this->modelDefinitionTypoScript['settings.']['registeredElements.'][$elementType . '.'][$scope])) {
-            return $this->modelDefinitionTypoScript['settings.']['registeredElements.'][$elementType . '.'][$scope];
-        }
-        return null;
-    }
-
-    /**
-     * Get a registered class name by a
-     * specific scope (validator or filter)
-     *
-     * @param string $name
-     * @param string $scope (registeredValidators, registeredFilters)
-     * @return mixed
-     */
-    public function getRegisteredClassName($name, $scope)
-    {
-        $name = strtolower($name);
-        if (isset($this->modelDefinitionTypoScript['settings.'][$scope . '.'][$name . '.']['className'])) {
-            return $this->modelDefinitionTypoScript['settings.'][$scope . '.'][$name . '.']['className'];
-        }
-        return null;
-    }
-
-    /**
-     * Render a TypoScript and resolve all references (eg. " < plugin.tx_form...") recursively
-     *
-     * @param array $typoScript
-     * @return array
-     * @todo Extract to core then...
-     */
-    protected function resolveTypoScriptReferences(array $typoScript)
-    {
-        $ignoreKeys = [];
-        foreach ($typoScript as $key => $value) {
-            if (isset($ignoreKeys[$key])) {
-                continue;
-            }
-            // i am a reference
-            if ($value[0] === '<') {
-                if (isset($typoScript[$key . '.'])) {
-                    $oldTypoScript = $typoScript[$key . '.'];
-                } else {
-                    $oldTypoScript = [];
-                }
-                // detect search level
-                $referencePath = trim(substr($value, 1));
-                $dotPosition = strpos($referencePath, '.');
-                if ($dotPosition === 0) {
-                    // same position x =< .y
-                    list($flatValue, $arrayValue) =  $this->typoScriptParser->getVal(substr($referencePath, 1), $typoScript);
-                } else {
-                    list($flatValue, $arrayValue) =  $this->typoScriptParser->getVal($referencePath, $GLOBALS['TSFE']->tmpl->setup);
-                }
-                if (is_array($arrayValue)) {
-                    $typoScript[$key . '.'] = array_replace_recursive($arrayValue, $oldTypoScript);
-                }
-                if ($flatValue[0] === '<') {
-                    $temporaryTypoScript = [
-                        'temp' => $flatValue,
-                        'temp.' => $typoScript[$key . '.'],
-                    ];
-                    $temporaryTypoScript = $this->resolveTypoScriptReferences($temporaryTypoScript);
-                    $arrayValue = array_replace_recursive($temporaryTypoScript['temp.'], $arrayValue, $oldTypoScript);
-                }
-                if (is_array($arrayValue)) {
-                    $typoScript[$key . '.'] = array_replace_recursive($arrayValue, $oldTypoScript);
-                } elseif (isset($flatValue)) {
-                    $typoScript[$key] = $flatValue;
-                } else {
-                    $typoScript[$key . '.'] = $oldTypoScript;
-                }
-            }
-            // if array, then look deeper
-            if (isset($typoScript[$key . '.'])) {
-                $ignoreKeys[$key . '.'] = true;
-                $typoScript[$key . '.'] = $this->resolveTypoScriptReferences($typoScript[$key . '.']);
-            } elseif (is_array($typoScript[$key])) {
-                // if array, then look deeper
-                $typoScript[$key] = $this->resolveTypoScriptReferences($typoScript[$key]);
-            }
-        }
-        return $typoScript;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Runtime/Exception/PropertyMappingException.php b/typo3/sysext/form/Classes/Domain/Runtime/Exception/PropertyMappingException.php
new file mode 100644
index 0000000000000000000000000000000000000000..60a22d53867cdb2f79533c0325c3607553b70081
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Runtime/Exception/PropertyMappingException.php
@@ -0,0 +1,29 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Runtime\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Exception;
+
+/**
+ * This Exception is thrown in the FormRuntime if the PropertyMapper throws
+ * a \TYPO3\CMS\Extbase\Property\Exception. It adds some more Information to
+ * better understand why the PropertyMapper failed to map the properties
+ *
+ * @api
+ */
+class PropertyMappingException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Domain/Runtime/FormRuntime.php b/typo3/sysext/form/Classes/Domain/Runtime/FormRuntime.php
new file mode 100644
index 0000000000000000000000000000000000000000..395f20c0a58fca1bace3b7e120b6362292b825dd
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Runtime/FormRuntime.php
@@ -0,0 +1,780 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Runtime;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Error\Result;
+use TYPO3\CMS\Extbase\Mvc\Controller\Arguments;
+use TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext;
+use TYPO3\CMS\Extbase\Mvc\Web\Request;
+use TYPO3\CMS\Extbase\Mvc\Web\Response;
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\Property\Exception as PropertyException;
+use TYPO3\CMS\Extbase\Reflection\PropertyReflection;
+use TYPO3\CMS\Extbase\Utility\ArrayUtility;
+use TYPO3\CMS\Form\Domain\Exception\RenderingException;
+use TYPO3\CMS\Form\Domain\Finishers\FinisherContext;
+use TYPO3\CMS\Form\Domain\Model\FormDefinition;
+use TYPO3\CMS\Form\Domain\Model\FormElements\FormElementInterface;
+use TYPO3\CMS\Form\Domain\Model\FormElements\Page;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface;
+use TYPO3\CMS\Form\Domain\Renderer\RendererInterface;
+use TYPO3\CMS\Form\Domain\Runtime\Exception\PropertyMappingException;
+use TYPO3\CMS\Form\Mvc\Validation\EmptyValidator;
+use TYPO3\CMS\Form\Utility\ArrayUtility as FormArrayUtility;
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+
+/**
+ * This class implements the *runtime logic* of a form, i.e. deciding which
+ * page is shown currently, what the current values of the form are, trigger
+ * validation and property mapping.
+ *
+ * You generally receive an instance of this class by calling {@link \TYPO3\CMS\Form\Domain\Model\FormDefinition::bind}.
+ *
+ * Rendering a Form
+ * ================
+ *
+ * That's easy, just call render() on the FormRuntime:
+ *
+ * /---code php
+ * $form = $formDefinition->bind($request, $response);
+ * $renderedForm = $form->render();
+ * \---
+ *
+ * Accessing Form Values
+ * =====================
+ *
+ * In order to get the values the user has entered into the form, you can access
+ * this object like an array: If a form field with the identifier *firstName*
+ * exists, you can do **$form['firstName']** to retrieve its current value.
+ *
+ * You can also set values in the same way.
+ *
+ * Rendering Internals
+ * ===================
+ *
+ * The FormRuntime asks the FormDefinition about the configured Renderer
+ * which should be used ({@link \TYPO3\CMS\Form\Domain\Model\FormDefinition::getRendererClassName}),
+ * and then trigger render() on this element.
+ *
+ * This makes it possible to declaratively define how a form should be rendered.
+ *
+ * Scope: frontend
+ * **This class is NOT meant to be sub classed by developers.**
+ * @api
+ */
+class FormRuntime implements RootRenderableInterface, \ArrayAccess
+{
+    const HONEYPOT_NAME_SESSION_IDENTIFIER = 'tx_form_honeypot_name_';
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * @var \TYPO3\CMS\Form\Domain\Model\FormDefinition
+     */
+    protected $formDefinition;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Mvc\Web\Request
+     */
+    protected $request;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Mvc\Web\Response
+     */
+    protected $response;
+
+    /**
+     * @var \TYPO3\CMS\Form\Domain\Runtime\FormState
+     */
+    protected $formState;
+
+    /**
+     * The current page is the page which will be displayed to the user
+     * during rendering.
+     *
+     * If $currentPage is NULL, the *last* page has been submitted and
+     * finishing actions need to take place. You should use $this->isAfterLastPage()
+     * instead of explicitely checking for NULL.
+     *
+     * @var \TYPO3\CMS\Form\Domain\Model\FormElements\Page
+     */
+    protected $currentPage = null;
+
+    /**
+     * Reference to the page which has been shown on the last request (i.e.
+     * we have to handle the submitted data from lastDisplayedPage)
+     *
+     * @var \TYPO3\CMS\Form\Domain\Model\FormElements\Page
+     */
+    protected $lastDisplayedPage = null;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Security\Cryptography\HashService
+     */
+    protected $hashService;
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Security\Cryptography\HashService $hashService
+     * @return void
+     * @internal
+     */
+    public function injectHashService(\TYPO3\CMS\Extbase\Security\Cryptography\HashService $hashService)
+    {
+        $this->hashService = $hashService;
+    }
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
+     * @internal
+     */
+    public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager)
+    {
+        $this->objectManager = $objectManager;
+    }
+
+    /**
+     * @param FormDefinition $formDefinition
+     * @param Request $request
+     * @param Response $response
+     * @api
+     */
+    public function __construct(FormDefinition $formDefinition, Request $request, Response $response)
+    {
+        $this->formDefinition = $formDefinition;
+        $arguments = $request->getArguments();
+        $this->request = clone $request;
+        $formIdentifier = $this->formDefinition->getIdentifier();
+        if (isset($arguments[$formIdentifier])) {
+            $this->request->setArguments($arguments[$formIdentifier]);
+        }
+
+        $this->response = $response;
+    }
+
+    /**
+     * @return void
+     * @internal
+     */
+    public function initializeObject()
+    {
+        $this->initializeFormStateFromRequest();
+        $this->initializeCurrentPageFromRequest();
+        $this->initializeHoneypotFromRequest();
+
+        if (!$this->isFirstRequest() && $this->getRequest()->getMethod() === 'POST') {
+            $this->processSubmittedFormValues();
+        }
+
+        $this->renderHoneypot();
+    }
+
+    /**
+     * @return void
+     */
+    protected function initializeFormStateFromRequest()
+    {
+        $serializedFormStateWithHmac = $this->request->getInternalArgument('__state');
+        if ($serializedFormStateWithHmac === null) {
+            $this->formState = GeneralUtility::makeInstance(FormState::class);
+        } else {
+            $serializedFormState = $this->hashService->validateAndStripHmac($serializedFormStateWithHmac);
+            $this->formState = unserialize(base64_decode($serializedFormState));
+        }
+    }
+
+    /**
+     * @return void
+     */
+    protected function initializeCurrentPageFromRequest()
+    {
+        if (!$this->formState->isFormSubmitted()) {
+            $this->currentPage = $this->formDefinition->getPageByIndex(0);
+            return;
+        }
+        $this->lastDisplayedPage = $this->formDefinition->getPageByIndex($this->formState->getLastDisplayedPageIndex());
+
+        // We know now that lastDisplayedPage is filled
+        $currentPageIndex = (int)$this->request->getInternalArgument('__currentPage');
+        if ($currentPageIndex > $this->lastDisplayedPage->getIndex() + 1) {
+            // We only allow jumps to following pages
+            $currentPageIndex = $this->lastDisplayedPage->getIndex() + 1;
+        }
+
+        // We now know that the user did not try to skip a page
+        if ($currentPageIndex === count($this->formDefinition->getPages())) {
+            // Last Page
+            $this->currentPage = null;
+        } else {
+            $this->currentPage = $this->formDefinition->getPageByIndex($currentPageIndex);
+        }
+    }
+
+    /**
+     * @return void
+     */
+    protected function initializeHoneypotFromRequest()
+    {
+        $renderingOptions = $this->formDefinition->getRenderingOptions();
+        if (!isset($renderingOptions['honeypot']['enable']) || $renderingOptions['honeypot']['enable'] === false || TYPO3_MODE === 'BE') {
+            return;
+        }
+
+        FormArrayUtility::assertAllArrayKeysAreValid($renderingOptions['honeypot'], ['enable', 'formElementToUse']);
+
+        if (!$this->isFirstRequest()) {
+            $elementsCount = count($this->lastDisplayedPage->getElements());
+            if ($elementsCount === 0) {
+                return;
+            }
+
+            $honeypotNameFromSession = $this->getHoneypotNameFromSession($this->lastDisplayedPage);
+            if ($honeypotNameFromSession) {
+                $honeypotElement = $this->lastDisplayedPage->createElement($honeypotNameFromSession, $renderingOptions['honeypot']['formElementToUse']);
+                $validator = $this->objectManager->get(EmptyValidator::class);
+                $honeypotElement->addValidator($validator);
+            }
+        }
+    }
+
+    /**
+     * @return void
+     */
+    protected function renderHoneypot()
+    {
+        $renderingOptions = $this->formDefinition->getRenderingOptions();
+        if (!isset($renderingOptions['honeypot']['enable']) || $renderingOptions['honeypot']['enable'] === false || TYPO3_MODE === 'BE') {
+            return;
+        }
+
+        FormArrayUtility::assertAllArrayKeysAreValid($renderingOptions['honeypot'], ['enable', 'formElementToUse']);
+
+        if (!$this->isAfterLastPage()) {
+            $elementsCount = count($this->currentPage->getElements());
+            if ($elementsCount === 0) {
+                return;
+            }
+
+            if (!$this->isFirstRequest()) {
+                $honeypotNameFromSession = $this->getHoneypotNameFromSession($this->lastDisplayedPage);
+                if ($honeypotNameFromSession) {
+                    $honeypotElement = $this->formDefinition->getElementByIdentifier($honeypotNameFromSession);
+                    if ($honeypotElement instanceof FormElementInterface) {
+                        $this->lastDisplayedPage->removeElement($honeypotElement);
+                    }
+                }
+            }
+
+            $elementsCount = count($this->currentPage->getElements());
+            $randomElementNumber = mt_rand(0, ($elementsCount - 1));
+            $honeypotName = substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'), 0, mt_rand(5, 26));
+
+            $referenceElement = $this->currentPage->getElements()[$randomElementNumber];
+            $honeypotElement = $this->currentPage->createElement($honeypotName, $renderingOptions['honeypot']['formElementToUse']);
+            $validator = $this->objectManager->get(EmptyValidator::class);
+
+            $honeypotElement->addValidator($validator);
+            if (mt_rand(0, 1) === 1) {
+                $this->currentPage->moveElementAfter($honeypotElement, $referenceElement);
+            } else {
+                $this->currentPage->moveElementBefore($honeypotElement, $referenceElement);
+            }
+            $this->setHoneypotNameInSession($this->currentPage, $honeypotName);
+        }
+    }
+
+    /**
+     * @param Page $page
+     * return null|string
+     */
+    protected function getHoneypotNameFromSession(Page $page)
+    {
+        if ($this->getTypoScriptFrontendController()->loginUser) {
+            $honeypotNameFromSession = $this->getTypoScriptFrontendController()->fe_user->getKey(
+                'user',
+                self::HONEYPOT_NAME_SESSION_IDENTIFIER . $this->getIdentifier() . $page->getIdentifier()
+            );
+        } else {
+            $honeypotNameFromSession = $this->getTypoScriptFrontendController()->fe_user->getKey(
+                'ses',
+                self::HONEYPOT_NAME_SESSION_IDENTIFIER . $this->getIdentifier() . $page->getIdentifier()
+            );
+        }
+        return $honeypotNameFromSession;
+    }
+
+    /**
+     * @param Page $page
+     * @param string $honeypotName
+     * @return void
+     */
+    protected function setHoneypotNameInSession(Page $page, string $honeypotName)
+    {
+        if ($this->getTypoScriptFrontendController()->loginUser) {
+            $this->getTypoScriptFrontendController()->fe_user->setKey(
+                'user',
+                self::HONEYPOT_NAME_SESSION_IDENTIFIER . $this->getIdentifier() . $page->getIdentifier(),
+                $honeypotName
+            );
+        } else {
+            $this->getTypoScriptFrontendController()->fe_user->setKey(
+                'ses',
+                self::HONEYPOT_NAME_SESSION_IDENTIFIER . $this->getIdentifier() . $page->getIdentifier(),
+                $honeypotName
+            );
+        }
+    }
+
+    /**
+     * Returns TRUE if the last page of the form has been submitted, otherwise FALSE
+     *
+     * @return bool
+     */
+    protected function isAfterLastPage(): bool
+    {
+        return $this->currentPage === null;
+    }
+
+    /**
+     * Returns TRUE if no previous page is stored in the FormState, otherwise FALSE
+     *
+     * @return bool
+     */
+    protected function isFirstRequest(): bool
+    {
+        return $this->lastDisplayedPage === null;
+    }
+
+    /**
+     * @return void
+     */
+    protected function processSubmittedFormValues()
+    {
+        $result = $this->mapAndValidatePage($this->lastDisplayedPage);
+        if ($result->hasErrors() && !$this->userWentBackToPreviousStep()) {
+            $this->currentPage = $this->lastDisplayedPage;
+            $this->request->setOriginalRequestMappingResults($result);
+        }
+    }
+
+    /**
+     * returns TRUE if the user went back to any previous step in the form.
+     *
+     * @return bool
+     */
+    protected function userWentBackToPreviousStep(): bool
+    {
+        return !$this->isAfterLastPage() && !$this->isFirstRequest() && $this->currentPage->getIndex() < $this->lastDisplayedPage->getIndex();
+    }
+
+    /**
+     * @param Page $page
+     * @return Result
+     * @throws PropertyMappingException
+     */
+    protected function mapAndValidatePage(Page $page): Result
+    {
+        $result = $this->objectManager->get(Result::class);
+        $requestArguments = $this->request->getArguments();
+
+        $propertyPathsForWhichPropertyMappingShouldHappen = [];
+        $registerPropertyPaths = function ($propertyPath) use (&$propertyPathsForWhichPropertyMappingShouldHappen) {
+            $propertyPathParts = explode('.', $propertyPath);
+            $accumulatedPropertyPathParts = [];
+            foreach ($propertyPathParts as $propertyPathPart) {
+                $accumulatedPropertyPathParts[] = $propertyPathPart;
+                $temporaryPropertyPath = implode('.', $accumulatedPropertyPathParts);
+                $propertyPathsForWhichPropertyMappingShouldHappen[$temporaryPropertyPath] = $temporaryPropertyPath;
+            }
+        };
+        foreach ($page->getElementsRecursively() as $element) {
+            $value = ArrayUtility::getValueByPath($requestArguments, $element->getIdentifier());
+            $element->onSubmit($this, $value, $requestArguments);
+
+            $this->formState->setFormValue($element->getIdentifier(), $value);
+            $registerPropertyPaths($element->getIdentifier());
+        }
+
+        // The more parts the path has, the more early it is processed
+        usort($propertyPathsForWhichPropertyMappingShouldHappen, function ($a, $b) {
+            return substr_count($b, '.') - substr_count($a, '.');
+        });
+
+        $processingRules = $this->formDefinition->getProcessingRules();
+
+        foreach ($propertyPathsForWhichPropertyMappingShouldHappen as $propertyPath) {
+            if (isset($processingRules[$propertyPath])) {
+                $processingRule = $processingRules[$propertyPath];
+                $value = $this->formState->getFormValue($propertyPath);
+                try {
+                    $value = $processingRule->process($value);
+                } catch (PropertyException $exception) {
+                    throw new PropertyMappingException(
+                        'Failed to process FormValue at "' . $propertyPath . '" from "' . gettype($value) . '" to "' . $processingRule->getDataType() . '"',
+                        1480024933,
+                        $exception
+                    );
+                }
+                $result->forProperty($propertyPath)->merge($processingRule->getProcessingMessages());
+                $this->formState->setFormValue($propertyPath, $value);
+            }
+        }
+
+        return $result;
+    }
+
+    /**
+     * Override the current page taken from the request, rendering the page with index $pageIndex instead.
+     *
+     * This is typically not needed in production code, but it is very helpful when displaying
+     * some kind of "preview" of the form.
+     *
+     * @param int $pageIndex
+     * @return void
+     * @api
+     */
+    public function overrideCurrentPage(int $pageIndex)
+    {
+        $this->currentPage = $this->formDefinition->getPageByIndex($pageIndex);
+    }
+
+    /**
+     * Render this form.
+     *
+     * @return null|string rendered form
+     * @throws RenderingException
+     * @api
+     */
+    public function render()
+    {
+        if ($this->isAfterLastPage()) {
+            $this->invokeFinishers();
+            return $this->response->getContent();
+        }
+
+        $this->formState->setLastDisplayedPageIndex($this->currentPage->getIndex());
+
+        if ($this->formDefinition->getRendererClassName() === null) {
+            throw new RenderingException(sprintf('The form definition "%s" does not have a rendererClassName set.', $this->formDefinition->getIdentifier()), 1326095912);
+        }
+        $rendererClassName = $this->formDefinition->getRendererClassName();
+        $renderer = $this->objectManager->get($rendererClassName);
+        if (!($renderer instanceof RendererInterface)) {
+            throw new RenderingException(sprintf('The renderer "%s" des not implement RendererInterface', $rendererClassName), 1326096024);
+        }
+
+        $controllerContext = $this->getControllerContext();
+
+        $renderer->setControllerContext($controllerContext);
+        $renderer->setFormRuntime($this);
+        return $renderer->render($this);
+    }
+
+    /**
+     * Executes all finishers of this form
+     *
+     * @return void
+     */
+    protected function invokeFinishers()
+    {
+        $finisherContext = $this->objectManager->get(FinisherContext::class,
+            $this,
+            $this->getControllerContext()
+        );
+        foreach ($this->formDefinition->getFinishers() as $finisher) {
+            $finisher->execute($finisherContext);
+            if ($finisherContext->isCancelled()) {
+                break;
+            }
+        }
+    }
+
+    /**
+     * @return string The identifier of underlying form
+     * @api
+     */
+    public function getIdentifier(): string
+    {
+        return $this->formDefinition->getIdentifier();
+    }
+
+    /**
+     * Get the request this object is bound to.
+     *
+     * This is mostly relevant inside Finishers, where you f.e. want to redirect
+     * the user to another page.
+     *
+     * @return Request the request this object is bound to
+     * @api
+     */
+    public function getRequest(): Request
+    {
+        return $this->request;
+    }
+
+    /**
+     * Get the response this object is bound to.
+     *
+     * This is mostly relevant inside Finishers, where you f.e. want to set response
+     * headers or output content.
+     *
+     * @return Response the response this object is bound to
+     * @api
+     */
+    public function getResponse(): Response
+    {
+        return $this->response;
+    }
+
+    /**
+     * Returns the currently selected page
+     *
+     * @return Page
+     * @api
+     */
+    public function getCurrentPage(): Page
+    {
+        return $this->currentPage;
+    }
+
+    /**
+     * Returns the previous page of the currently selected one or NULL if there is no previous page
+     *
+     * @return null|Page
+     * @api
+     */
+    public function getPreviousPage()
+    {
+        $previousPageIndex = $this->currentPage->getIndex() - 1;
+        if ($this->formDefinition->hasPageWithIndex($previousPageIndex)) {
+            return $this->formDefinition->getPageByIndex($previousPageIndex);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the next page of the currently selected one or NULL if there is no next page
+     *
+     * @return null|Page
+     * @api
+     */
+    public function getNextPage()
+    {
+        $nextPageIndex = $this->currentPage->getIndex() + 1;
+        if ($this->formDefinition->hasPageWithIndex($nextPageIndex)) {
+            return $this->formDefinition->getPageByIndex($nextPageIndex);
+        }
+        return null;
+    }
+
+    /**
+     * @return ControllerContext
+     */
+    protected function getControllerContext(): ControllerContext
+    {
+        $uriBuilder = $this->objectManager->get(UriBuilder::class);
+        $uriBuilder->setRequest($this->request);
+        $controllerContext = $this->objectManager->get(ControllerContext::class);
+        $controllerContext->setRequest($this->request);
+        $controllerContext->setResponse($this->response);
+        $controllerContext->setArguments($this->objectManager->get(Arguments::class, []));
+        $controllerContext->setUriBuilder($uriBuilder);
+        return $controllerContext;
+    }
+
+    /**
+     * Abstract "type" of this Renderable. Is used during the rendering process
+     * to determine the template file or the View PHP class being used to render
+     * the particular element.
+     *
+     * @return string
+     * @api
+     */
+    public function getType(): string
+    {
+        return $this->formDefinition->getType();
+    }
+
+    /**
+     * @param string $identifier
+     * @return bool
+     * @internal
+     */
+    public function offsetExists($identifier)
+    {
+        if ($this->getElementValue($identifier) !== null) {
+            return true;
+        }
+
+        if (is_callable([$this, 'get' . ucfirst($identifier)])) {
+            return true;
+        }
+        if (is_callable([$this, 'has' . ucfirst($identifier)])) {
+            return true;
+        }
+        if (is_callable([$this, 'is' . ucfirst($identifier)])) {
+            return true;
+        }
+        if (property_exists($this, $identifier)) {
+            $propertyReflection = new PropertyReflection($this, $identifier);
+            return $propertyReflection->isPublic();
+        }
+
+        return false;
+    }
+
+    /**
+     * @param string $identifier
+     * @return mixed
+     * @internal
+     */
+    public function offsetGet($identifier)
+    {
+        if ($this->getElementValue($identifier) !== null) {
+            return $this->getElementValue($identifier);
+        }
+        $getterMethodName = 'get' . ucfirst($identifier);
+        if (is_callable([$this, $getterMethodName])) {
+            return $this->{$getterMethodName}();
+        }
+        return null;
+    }
+
+    /**
+     * @param string $identifier
+     * @param mixed $value
+     * @return void
+     * @internal
+     */
+    public function offsetSet($identifier, $value)
+    {
+        $this->formState->setFormValue($identifier, $value);
+    }
+
+    /**
+     * @param string $identifier
+     * @return void
+     * @internal
+     */
+    public function offsetUnset($identifier)
+    {
+        $this->formState->setFormValue($identifier, null);
+    }
+
+    /**
+     * Returns the value of the specified element
+     *
+     * @param string $identifier
+     * @return mixed
+     * @api
+     */
+    public function getElementValue(string $identifier)
+    {
+        $formValue = $this->formState->getFormValue($identifier);
+        if ($formValue !== null) {
+            return $formValue;
+        }
+        return $this->formDefinition->getElementDefaultValueByIdentifier($identifier);
+    }
+
+    /**
+     * @return array<Page> The Form's pages in the correct order
+     * @api
+     */
+    public function getPages(): array
+    {
+        return $this->formDefinition->getPages();
+    }
+
+    /**
+     * @return FormState
+     * @internal
+     */
+    public function getFormState(): FormState
+    {
+        return $this->formState;
+    }
+
+    /**
+     * Get all rendering options
+     *
+     * @return array associative array of rendering options
+     * @api
+     */
+    public function getRenderingOptions(): array
+    {
+        return $this->formDefinition->getRenderingOptions();
+    }
+
+    /**
+     * Get the renderer class name to be used to display this renderable;
+     * must implement RendererInterface
+     *
+     * @return string the renderer class name
+     * @api
+     */
+    public function getRendererClassName(): string
+    {
+        return $this->formDefinition->getRendererClassName();
+    }
+
+    /**
+     * Get the label which shall be displayed next to the form element
+     *
+     * @return string
+     * @api
+     */
+    public function getLabel(): string
+    {
+        return $this->formDefinition->getLabel();
+    }
+
+    /**
+     * Get the underlying form definition from the runtime
+     *
+     * @return FormDefinition
+     * @api
+     */
+    public function getFormDefinition(): FormDefinition
+    {
+        return $this->formDefinition;
+    }
+
+    /**
+     * This is a callback that is invoked by the Renderer before the corresponding element is rendered.
+     * Use this to access previously submitted values and/or modify the $formRuntime before an element
+     * is outputted to the browser.
+     *
+     * @param FormRuntime $formRuntime
+     * @return void
+     * @api
+     */
+    public function beforeRendering(FormRuntime $formRuntime)
+    {
+    }
+
+    /**
+     * @return TypoScriptFrontendController
+     */
+    protected function getTypoScriptFrontendController()
+    {
+        return $GLOBALS['TSFE'];
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Runtime/FormState.php b/typo3/sysext/form/Classes/Domain/Runtime/FormState.php
new file mode 100644
index 0000000000000000000000000000000000000000..ff6b43733fa00aebf01503983f9e3974951ac28b
--- /dev/null
+++ b/typo3/sysext/form/Classes/Domain/Runtime/FormState.php
@@ -0,0 +1,100 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Domain\Runtime;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Utility\ArrayUtility;
+
+/**
+ * The current state of the form which is attached to the {@link FormRuntime}
+ * and saved in a session or the client.
+ *
+ * Scope: frontend
+ * **This class is NOT meant to be sub classed by developers.**
+ * @internal
+ */
+class FormState
+{
+
+    /**
+     * Constant which means that we are currently not on any page; i.e. the form
+     * has never rendered before.
+     */
+    const NOPAGE = -1;
+
+    /**
+     * The last displayed page index
+     *
+     * @var int
+     */
+    protected $lastDisplayedPageIndex = self::NOPAGE;
+
+    /**
+     * @var array
+     */
+    protected $formValues = [];
+
+    /**
+     * @return bool FALSE if the form has never been submitted before, TRUE otherwise
+     */
+    public function isFormSubmitted(): bool
+    {
+        return $this->lastDisplayedPageIndex !== self::NOPAGE;
+    }
+
+    /**
+     * @return int
+     */
+    public function getLastDisplayedPageIndex(): int
+    {
+        return $this->lastDisplayedPageIndex;
+    }
+
+    /**
+     * @param int $lastDisplayedPageIndex
+     * @return void
+     */
+    public function setLastDisplayedPageIndex(int $lastDisplayedPageIndex)
+    {
+        $this->lastDisplayedPageIndex = $lastDisplayedPageIndex;
+    }
+
+    /**
+     * @return array
+     */
+    public function getFormValues(): array
+    {
+        return $this->formValues;
+    }
+
+    /**
+     * @param string $propertyPath
+     * @param mixed $value
+     * @return void
+     */
+    public function setFormValue(string $propertyPath, $value)
+    {
+        $this->formValues = ArrayUtility::setValueByPath($this->formValues, $propertyPath, $value);
+    }
+
+    /**
+     * @param string $propertyPath
+     * @return mixed
+     */
+    public function getFormValue(string $propertyPath)
+    {
+        return ArrayUtility::getValueByPath($this->formValues, $propertyPath);
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/AbstractValidator.php b/typo3/sysext/form/Classes/Domain/Validator/AbstractValidator.php
deleted file mode 100644
index adfb477a54ee3d676a1c6d9e76a9d99c976cfe1d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/AbstractValidator.php
+++ /dev/null
@@ -1,116 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
-use TYPO3\CMS\Form\Utility\FormUtility;
-
-abstract class AbstractValidator extends \TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator
-{
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate';
-
-    /**
-     * @var FormUtility
-     */
-    protected $formUtility;
-
-    /**
-     * @var mixed
-     */
-    protected $rawArgument;
-
-    /**
-     * @var array
-     */
-    protected $supportedOptions = [
-        'element' => ['', 'The name of the element', 'string', true],
-        'errorMessage' => ['', 'The error message', 'array', true],
-    ];
-
-    /**
-     * This validator always needs to be executed even if the given value is empty.
-     * See AbstractValidator::validate()
-     *
-     * @var bool
-     */
-    protected $acceptsEmptyValues = false;
-
-    /**
-     * @param mixed $rawArgument
-     */
-    public function setRawArgument($rawArgument)
-    {
-        $this->rawArgument = $rawArgument;
-    }
-
-    /**
-     * @param FormUtility $formUtility
-     */
-    public function setFormUtility(FormUtility $formUtility)
-    {
-        $this->formUtility = $formUtility;
-    }
-
-    /**
-     * Substitute makers in the message text
-     * In some cases this method will be override by rule class
-     *
-     * @param string $message Message text with markers
-     * @return string Message text with substituted markers
-     */
-    public function substituteMarkers($message)
-    {
-        return $message;
-    }
-
-    /**
-     * Get the local language label(s) for the message
-     * In some cases this method will be override by rule class
-     *
-     * @param string $type The type
-     * @return string The local language message label
-     */
-    public function getLocalLanguageLabel($type = '')
-    {
-        $label = static::LOCALISATION_OBJECT_NAME . '.' . $type;
-        $message = LocalizationUtility::translate($label, 'form');
-        return $message;
-    }
-
-    /**
-     * Set the message, like 'required' for the validation rule
-     * and substitutes markers for values, like %maximum
-     *
-     *
-     * @param mixed $message Message as string or TS
-     * @param NULL|string $type Name of the cObj
-     * @param string $messageType message or error
-     * @return string
-     */
-    public function renderMessage($message = null, $type = null, $messageType = 'message')
-    {
-        $message = $this->formUtility->renderItem(
-            $message,
-            $type,
-            $this->getLocalLanguageLabel($messageType)
-        );
-        return $this->substituteMarkers($message);
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/AlphabeticValidator.php b/typo3/sysext/form/Classes/Domain/Validator/AlphabeticValidator.php
deleted file mode 100644
index 57085725ec6db89c807a1eec683af85a85106a14..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/AlphabeticValidator.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class AlphabeticValidator extends AbstractValidator
-{
-    /**
-     * @var array
-     */
-    protected $supportedOptions = [
-        'element' => ['', 'The name of the element', 'string', true],
-        'errorMessage' => ['', 'The error message', 'array', true],
-        'allowWhiteSpace' => ['', 'Whitespaces are allowed', 'boolean', false],
-    ];
-
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_alphabetic';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        if (
-            !isset($this->options['allowWhiteSpace'])
-            || $this->options['allowWhiteSpace'] === ''
-            || (int)$this->options['allowWhiteSpace'] === 0
-        ) {
-            $this->options['allowWhiteSpace'] = false;
-        } else {
-            $this->options['allowWhiteSpace'] = true;
-        }
-
-        $whiteSpace = $this->options['allowWhiteSpace'] ? '\\s' : '';
-        $pattern = '/[^\pL' . $whiteSpace . ']/u';
-        $compareValue = preg_replace($pattern, '', (string)$value);
-
-        if ($compareValue !== $value) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1442004245
-            );
-        }
-    }
-
-    /**
-     * Get the local language label(s) for the message
-     * Overrides the abstract
-     *
-     * @param string $type The type
-     * @return string The local language message label
-     * @see \TYPO3\CMS\Form\Validation\AbstractValidator::_getLocalLanguageLabel()
-     */
-    public function getLocalLanguageLabel($type = '')
-    {
-        $label = static::LOCALISATION_OBJECT_NAME . '.message';
-        $messages[] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label, 'form');
-        if ($this->options['allowWhiteSpace']) {
-            $messages[] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 2, 'form');
-        }
-        $message = implode(', ', $messages);
-        return $message;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/AlphanumericValidator.php b/typo3/sysext/form/Classes/Domain/Validator/AlphanumericValidator.php
deleted file mode 100644
index 1bd18c8fc97ee0b0700afbbd92f445d3eeb64060..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/AlphanumericValidator.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class AlphanumericValidator extends AbstractValidator
-{
-    /**
-     * @var array
-     */
-    protected $supportedOptions = [
-        'element' => ['', 'The name of the element', 'string', true],
-        'errorMessage' => ['', 'The error message', 'array', true],
-        'allowWhiteSpace' => ['', 'Whitespaces are allowed', 'boolean', false],
-    ];
-
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_alphanumeric';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        if (
-            !isset($this->options['allowWhiteSpace'])
-            || $this->options['allowWhiteSpace'] === ''
-            || (int)$this->options['allowWhiteSpace'] === 0
-        ) {
-            $this->options['allowWhiteSpace'] = false;
-        } else {
-            $this->options['allowWhiteSpace'] = true;
-        }
-
-        $whiteSpace = $this->options['allowWhiteSpace'] ? '\\s' : '';
-        $pattern = '/[^\pL\d)' . $whiteSpace . ']/u';
-        $compareValue = preg_replace($pattern, '', (string)$value);
-
-        if ($compareValue !== $value) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1442004457
-            );
-        }
-    }
-
-    /**
-     * Get the local language label(s) for the message
-     * Overrides the abstract
-     *
-     * @param string $type The type
-     * @return string The local language message label
-     * @see \TYPO3\CMS\Form\Validation\AbstractValidator::_getLocalLanguageLabel()
-     */
-    public function getLocalLanguageLabel($type = '')
-    {
-        $label = static::LOCALISATION_OBJECT_NAME . '.message';
-        $messages[] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label, 'form');
-        if ($this->options['allowWhiteSpace']) {
-            $messages[] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 2, 'form');
-        }
-        $message = implode(', ', $messages);
-        return $message;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/BetweenValidator.php b/typo3/sysext/form/Classes/Domain/Validator/BetweenValidator.php
deleted file mode 100644
index b528845ebeb1085c951dd78e842a2a3bad359958..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/BetweenValidator.php
+++ /dev/null
@@ -1,109 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class BetweenValidator extends AbstractValidator
-{
-    /**
-     * @var array
-     */
-    protected $supportedOptions = [
-        'element' => ['', 'The name of the element', 'string', true],
-        'errorMessage' => ['', 'The error message', 'array', true],
-        'minimum' => ['', 'The minimum value', 'integer', true],
-        'maximum' => ['', 'The maximum value', 'integer', true],
-        'inclusive' => ['', 'Minimum and maximum value are inclusive in comparison', 'integer', false],
-    ];
-
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_between';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        if (
-            !isset($this->options['inclusive'])
-            || $this->options['inclusive'] === ''
-            || (int)$this->options['inclusive'] === 0
-        ) {
-            if ($value <= $this->options['minimum'] || $value >= $this->options['maximum']) {
-                $this->addError(
-                    $this->renderMessage(
-                        $this->options['errorMessage'][0],
-                        $this->options['errorMessage'][1],
-                        'error'
-                    ),
-                    1442003544
-                );
-            }
-        } else {
-            if ($value < $this->options['minimum'] || $value > $this->options['maximum']) {
-                $this->addError(
-                    $this->renderMessage(
-                        $this->options['errorMessage'][0],
-                        $this->options['errorMessage'][1],
-                        'error'
-                    ),
-                    1442003545
-                );
-            }
-        }
-    }
-
-    /**
-     * Get the local language label(s) for the message
-     * Overrides the abstract
-     *
-     * @param string $type The type
-     * @return string The local language message label
-     * @see \TYPO3\CMS\Form\Validation\AbstractValidator::_getLocalLanguageLabel()
-     */
-    public function getLocalLanguageLabel($type = '')
-    {
-        $label = static::LOCALISATION_OBJECT_NAME . '.' . $type;
-        $messages[] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label, 'form');
-        if ($this->inclusive) {
-            $messages[] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 2, 'form');
-        }
-        $message = implode(', ', $messages);
-        return $message;
-    }
-
-    /**
-     * Substitute makers in the message text
-     * Overrides the abstract
-     *
-     * @param string $message Message text with markers
-     * @return string Message text with substituted markers
-     */
-    public function substituteMarkers($message)
-    {
-        return str_replace(
-            ['%minimum', '%maximum'],
-            [$this->options['minimum'], $this->options['maximum']],
-            $message
-        );
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/DateValidator.php b/typo3/sysext/form/Classes/Domain/Validator/DateValidator.php
deleted file mode 100644
index fca3f0d7653965050be75fbcb13b1106c6cc38b1..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/DateValidator.php
+++ /dev/null
@@ -1,154 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class DateValidator extends AbstractValidator
-{
-    /**
-     * @var array
-     */
-    protected $supportedOptions = [
-        'element' => ['', 'The name of the element', 'string', true],
-        'errorMessage' => ['', 'The error message', 'array', true],
-        'format' => ['', 'The maximum value', 'string', true],
-    ];
-
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_date';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        if (
-            $this->options['format'] === null
-            || $this->options['format'] === ''
-        ) {
-            $this->options['format'] = '%e-%m-%Y';
-        }
-
-        if (function_exists('strptime')) {
-            $parsedDate = strptime($value, $this->options['format']);
-            $parsedDateYear = $parsedDate['tm_year'] + 1900;
-            $parsedDateMonth = $parsedDate['tm_mon'] + 1;
-            $parsedDateDay = $parsedDate['tm_mday'];
-            if (!checkdate($parsedDateMonth, $parsedDateDay, $parsedDateYear)) {
-                $this->addError(
-                    $this->renderMessage(
-                        $this->options['errorMessage'][0],
-                        $this->options['errorMessage'][1],
-                        'error'
-                    ),
-                    1442001386
-                );
-                return;
-            }
-        } else {
-            // %a => D : An abbreviated textual representation of the day (conversion works only for english)
-            // %A => l : A full textual representation of the day (conversion works only for english)
-            // %d => d : Day of the month, 2 digits with leading zeros
-            // %e => j : Day of the month, 2 digits without leading zeros
-            // %j => z : Day of the year, 3 digits with leading zeros
-            // %b => M : Abbreviated month name, based on the locale (conversion works only for english)
-            // %B => F : Full month name, based on the locale (conversion works only for english)
-            // %h => M : Abbreviated month name, based on the locale (an alias of %b) (conversion works only for english)
-            // %m => m : Two digit representation of the month
-            // %y => y : Two digit representation of the year
-            // %Y => Y : Four digit representation for the year
-            $dateTimeFormat = str_replace(
-                ['%a', '%A', '%d', '%e', '%j', '%b', '%B', '%h', '%m', '%y', '%Y'],
-                ['D', 'l', 'd', 'j', 'z', 'M', 'F', 'M', 'm', 'y', 'Y'],
-                $this->options['format']
-            );
-            $dateTimeObject = date_create_from_format($dateTimeFormat, $value);
-            if ($dateTimeObject === false) {
-                $this->addError(
-                    $this->renderMessage(
-                        $this->options['errorMessage'][0],
-                        $this->options['errorMessage'][1],
-                        'error'
-                    ),
-                    1442001386
-                );
-                return;
-            }
-
-            if ($value !== $dateTimeObject->format($dateTimeFormat)) {
-                $this->addError(
-                    $this->renderMessage(
-                        $this->options['errorMessage'][0],
-                        $this->options['errorMessage'][1],
-                        'error'
-                    ),
-                    1442001386
-                );
-            }
-        }
-    }
-
-    /**
-     * Substitute makers in the message text
-     * Overrides the abstract
-     *
-     * @param string $message Message text with markers
-     * @return string Message text with substituted markers
-     */
-    public function substituteMarkers($message)
-    {
-        $humanReadableDateFormat = $this->humanReadableDateFormat($this->options['format']);
-        $message = str_replace('%format', $humanReadableDateFormat, $message);
-        return $message;
-    }
-
-    /**
-     * Converts strftime date format to human readable format
-     * according to local language.
-     *
-     * Example for default language: %e-%m-%Y becomes d-mm-yyyy
-     *
-     * @param string $format strftime format
-     * @return string Human readable format
-     */
-    protected function humanReadableDateFormat($format)
-    {
-        $label = self::LOCALISATION_OBJECT_NAME . '.strftime.';
-        $pairs = [
-            '%A' => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 'A', 'form'),
-            '%a' => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 'a', 'form'),
-            '%d' => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 'd', 'form'),
-            '%e' => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 'e', 'form'),
-            '%B' => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 'B', 'form'),
-            '%b' => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 'b', 'form'),
-            '%m' => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 'm', 'form'),
-            '%Y' => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 'Y', 'form'),
-            '%y' => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 'y', 'form'),
-            '%H' => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 'H', 'form'),
-            '%I' => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 'I', 'form'),
-            '%M' => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 'M', 'form'),
-            '%S' => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 'S', 'form')
-        ];
-        $humanReadableFormat = str_replace(array_keys($pairs), array_values($pairs), $format);
-        return $humanReadableFormat;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/DigitValidator.php b/typo3/sysext/form/Classes/Domain/Validator/DigitValidator.php
deleted file mode 100644
index 3654bcae4a10739419cd328ba5217b4d833dc694..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/DigitValidator.php
+++ /dev/null
@@ -1,47 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class DigitValidator extends AbstractValidator
-{
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_digit';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        $compareValue = preg_replace('/[^0-9]/', '', (string)$value);
-        if ($compareValue !== $value) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1442000838
-            );
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/EmailValidator.php b/typo3/sysext/form/Classes/Domain/Validator/EmailValidator.php
deleted file mode 100644
index edb05fcb18182fc1b9563a4d6a337abc6e9f01a0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/EmailValidator.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-/**
- * Class EmailValidator
- */
-class EmailValidator extends AbstractValidator
-{
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_email';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        if (empty($value) || !is_string($value)) {
-            return;
-        }
-
-        if (!GeneralUtility::validEmail($value)) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1442000235
-            );
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/EqualsValidator.php b/typo3/sysext/form/Classes/Domain/Validator/EqualsValidator.php
deleted file mode 100644
index 4f5ea32b9c8764dd934b295b1d39131f34787f6d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/EqualsValidator.php
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class EqualsValidator extends AbstractValidator
-{
-    /**
-     * @var array
-     */
-    protected $supportedOptions = [
-        'element' => ['', 'The name of the element', 'string', true],
-        'errorMessage' => ['', 'The error message', 'array', true],
-        'field' => ['', 'The field to be compared', 'string', true],
-    ];
-
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_equals';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        $comparisonValue = $this->rawArgument[$this->options['field']];
-        if ($value !== $comparisonValue) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1442005826
-            );
-        }
-    }
-
-    /**
-     * Substitute makers in the message text
-     * Overrides the abstract
-     *
-     * @param string $message Message text with markers
-     * @return string Message text with substituted markers
-     */
-    public function substituteMarkers($message)
-    {
-        $message = str_replace('%field', $this->options['field'], $message);
-        return $message;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/FileAllowedTypesValidator.php b/typo3/sysext/form/Classes/Domain/Validator/FileAllowedTypesValidator.php
deleted file mode 100644
index b7b58f245f7d77007dcd205ee874f4ee494a5ffc..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/FileAllowedTypesValidator.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-class FileAllowedTypesValidator extends AbstractValidator
-{
-    /**
-     * @var array
-     */
-    protected $supportedOptions = [
-        'element' => ['', 'The name of the element', 'string', true],
-        'errorMessage' => ['', 'The error message', 'array', true],
-        'types' => ['', 'The allowed file types', 'string', true],
-    ];
-
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_fileallowedtypes';
-
-    /**
-     * Check if the file mime type is allowed.
-     *
-     * The mime type is set in the propertymapper
-     *
-     * @see TYPO3\CMS\Form\Domain\Property\TypeConverter::convertFrom
-     *
-     * @param array $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        $allowedTypes = strtolower($this->options['types']);
-        $allowedMimeTypes = GeneralUtility::trimExplode(',', $allowedTypes, true);
-        $fileMimeType = !empty($value['type']) ? strtolower($value['type']) : '';
-
-        if (!in_array($fileMimeType, $allowedMimeTypes, true)) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1442006702
-            );
-        }
-    }
-
-    /**
-     * Substitute makers in the message text
-     * Overrides the abstract
-     *
-     * @param string $message Message text with markers
-     * @return string Message text with substituted markers
-     */
-    public function substituteMarkers($message)
-    {
-        $allowedTypes = strtolower($this->options['types']);
-        $allowedMimeTypes = GeneralUtility::trimExplode(',', $allowedTypes);
-        $allowedTypesStringForDisplay = implode(', ', $allowedMimeTypes);
-        $message = str_replace('%allowedTypes', $allowedTypesStringForDisplay, $message);
-
-        return $message;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/FileMaximumSizeValidator.php b/typo3/sysext/form/Classes/Domain/Validator/FileMaximumSizeValidator.php
deleted file mode 100644
index 38d1ba9fb71bad962d1274d662ad4f08e1cc398f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/FileMaximumSizeValidator.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-class FileMaximumSizeValidator extends AbstractValidator
-{
-    /**
-     * @var array
-     */
-    protected $supportedOptions = [
-        'element' => ['', 'The name of the element', 'string', true],
-        'errorMessage' => ['', 'The error message', 'array', true],
-        'maximum' => ['', 'The maximum file size', 'integer', true],
-    ];
-
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_filemaximumsize';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        $fileValue = $this->rawArgument[$this->options['element']];
-        $value = $fileValue['size'];
-        if ($value > (int)$this->options['maximum']) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1442006702
-            );
-        }
-    }
-
-    /**
-     * Substitute makers in the message text
-     * Overrides the abstract
-     *
-     * @param string $message Message text with markers
-     * @return string Message text with substituted markers
-     */
-    public function substituteMarkers($message)
-    {
-        $message = str_replace('%maximum', GeneralUtility::formatSize($this->options['maximum']), $message);
-        return $message;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/FileMinimumSizeValidator.php b/typo3/sysext/form/Classes/Domain/Validator/FileMinimumSizeValidator.php
deleted file mode 100644
index 5aac7591a05ed57551376f98f38bffc16ae25a73..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/FileMinimumSizeValidator.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-class FileMinimumSizeValidator extends AbstractValidator
-{
-    /**
-     * @var array
-     */
-    protected $supportedOptions = [
-        'element' => ['', 'The name of the element', 'string', true],
-        'errorMessage' => ['', 'The error message', 'array', true],
-        'minimum' => ['', 'The minimum file size', 'integer', true],
-    ];
-
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_fileminimumsize';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        $fileValue = $this->rawArgument[$this->options['element']];
-        $value = $fileValue['size'];
-        if ($value < (int)$this->options['minimum']) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1442006702
-            );
-        }
-    }
-
-    /**
-     * Substitute makers in the message text
-     * Overrides the abstract
-     *
-     * @param string $message Message text with markers
-     * @return string Message text with substituted markers
-     */
-    public function substituteMarkers($message)
-    {
-        $message = str_replace('%minimum', GeneralUtility::formatSize($this->options['minimum']), $message);
-        return $message;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/FloatValidator.php b/typo3/sysext/form/Classes/Domain/Validator/FloatValidator.php
deleted file mode 100644
index 4322d718c497a3da2a22bfbea2e3ee9126a0c90b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/FloatValidator.php
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class FloatValidator extends AbstractValidator
-{
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_float';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        $locale = localeconv();
-        $valueFiltered = str_replace(
-            [
-                $locale['thousands_sep'],
-                $locale['mon_thousands_sep'],
-                $locale['decimal_point'],
-                $locale['mon_decimal_point']
-            ],
-            [
-                '',
-                '',
-                '.',
-                '.'
-            ],
-            $value
-        );
-        if ($value != strval((float)$valueFiltered)) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1442002070
-            );
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/GreaterThanValidator.php b/typo3/sysext/form/Classes/Domain/Validator/GreaterThanValidator.php
deleted file mode 100644
index bd35699a9bd77505f498ad29b6d2e6a4d7cef361..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/GreaterThanValidator.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class GreaterThanValidator extends AbstractValidator
-{
-    /**
-     * @var array
-     */
-    protected $supportedOptions = [
-        'element' => ['', 'The name of the element', 'string', true],
-        'errorMessage' => ['', 'The error message', 'array', true],
-        'minimum' => ['', 'The minimum value', 'integer', true],
-    ];
-
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_greaterthan';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        if ((int)$value <= (int)$this->options['minimum']) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1442002213
-            );
-        }
-    }
-
-    /**
-     * Substitute makers in the message text
-     * Overrides the abstract
-     *
-     * @param string $message Message text with markers
-     * @return string Message text with substituted markers
-     */
-    public function substituteMarkers($message)
-    {
-        $message = str_replace('%minimum', $this->options['minimum'], $message);
-        return $message;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/InArrayValidator.php b/typo3/sysext/form/Classes/Domain/Validator/InArrayValidator.php
deleted file mode 100644
index ef3c9d3cf90f71f2f443f08c33dcddfb3e6526f0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/InArrayValidator.php
+++ /dev/null
@@ -1,124 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Charset\CharsetConverter;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-
-class InArrayValidator extends AbstractValidator
-{
-    /**
-     * @var array
-     */
-    protected $supportedOptions = [
-        'element' => ['', 'The name of the element', 'string', true],
-        'errorMessage' => ['', 'The error message', 'array', true],
-        'array' => ['', 'The array values from the wizard configuration (array = test1,test2)', 'string', false],
-        'array.' => ['', 'The array values from the documented configuration', 'array', false],
-        'strict' => ['', 'Compare types', 'boolean', false],
-        'ignorecase' => ['', 'Ignore cases', 'boolean', false]
-    ];
-
-    /**
-     * @var CharsetConverter
-     */
-    protected $charsetConverter;
-
-    /**
-     * Constructor
-     *
-     * Creates charsetConverter object if option ignorecase is set
-     *
-     * @param array $options
-     * @throws \TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationOptionsException
-     */
-    public function __construct(array $options)
-    {
-        parent::__construct($options);
-        if (!empty($this->options['ignorecase'])) {
-            $this->charsetConverter = GeneralUtility::makeInstance(CharsetConverter::class);
-        }
-    }
-
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_inarray';
-
-    /**
-     * Check if $value is valid. If it is not valid, add an error to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        if (empty($value)) {
-            return;
-        }
-
-        /**
-         * A single select results in a string,
-         * a multiselect in an array.
-         * In both cases, the operations will be processed on an array.
-         */
-        if (is_string($value)) {
-            $value = [$value];
-        }
-
-        /**
-         * The form wizard generates the following configuration:
-         *   array = test1,test2
-         * In this case the string has to be exploded.
-         * The following configuration was documented:
-         *   array {
-         *     1 = TYPO3 4.5 LTS
-         *     2 = TYPO3 6.2 LTS
-         *     3 = TYPO3 7 LTS
-         *   }
-         * In this case there is already an array but the "options" key differs.
-         */
-        $allowedOptionsArray = [];
-        if (!empty($this->options['array']) && is_string($this->options['array'])) {
-            $allowedOptionsArray = GeneralUtility::trimExplode(',', $this->options['array'], true);
-        } elseif (!empty($this->options['array.']) && is_array($this->options['array.'])) {
-            $allowedOptionsArray = $this->options['array.'];
-        }
-
-        if (!empty($this->options['ignorecase'])) {
-            foreach ($value as &$incomingArrayValue) {
-                $incomingArrayValue = $this->charsetConverter->conv_case('utf-8', $incomingArrayValue, 'toLower');
-            }
-            foreach ($allowedOptionsArray as &$option) {
-                $option = $this->charsetConverter->conv_case('utf-8', $option, 'toLower');
-            }
-        }
-
-        foreach ($value as $incomingArrayValue) {
-            if (!in_array($incomingArrayValue, $allowedOptionsArray, !empty($this->options['strict']))) {
-                $this->addError(
-                    $this->renderMessage(
-                        $this->options['errorMessage'][0],
-                        $this->options['errorMessage'][1],
-                        'error'
-                    ),
-                    1442002594
-                );
-            }
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/IntegerValidator.php b/typo3/sysext/form/Classes/Domain/Validator/IntegerValidator.php
deleted file mode 100644
index 87106fa9c146ef4a9554a0fc179fb4053b164611..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/IntegerValidator.php
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class IntegerValidator extends AbstractValidator
-{
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_integer';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        $locale = localeconv();
-        $valueFiltered = str_replace(
-            [
-                $locale['thousands_sep'],
-                $locale['mon_thousands_sep'],
-                $locale['decimal_point'],
-                $locale['mon_decimal_point']
-            ],
-            [
-                '',
-                '',
-                '.',
-                '.'
-            ],
-            $value
-        );
-        if (strval((int)$valueFiltered) != $valueFiltered) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1442000119
-            );
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/IpValidator.php b/typo3/sysext/form/Classes/Domain/Validator/IpValidator.php
deleted file mode 100644
index 9cdebec40b85d0b951f82b14caada45b5c839b53..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/IpValidator.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class IpValidator extends AbstractValidator
-{
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_ip';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        if (!preg_match('/\\b(([01]?\\d?\\d|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d?\\d|2[0-4]\\d|25[0-5])\\b/', $value)) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1441999896
-            );
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/LengthValidator.php b/typo3/sysext/form/Classes/Domain/Validator/LengthValidator.php
deleted file mode 100644
index 5639aa07d56c90e0a8479412b881a075f56cf74a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/LengthValidator.php
+++ /dev/null
@@ -1,128 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class LengthValidator extends AbstractValidator
-{
-    /**
-     * TYPO3 charset encoding object
-     *
-     * @var \TYPO3\CMS\Core\Charset\CharsetConverter
-     */
-    protected $charsetConverter = null;
-
-    /**
-     * @param \TYPO3\CMS\Core\Charset\CharsetConverter $charsetConverter
-     * @return void
-     */
-    public function injectCharsetConverter(\TYPO3\CMS\Core\Charset\CharsetConverter $charsetConverter)
-    {
-        $this->charsetConverter = $charsetConverter;
-    }
-
-    /**
-     * @var array
-     */
-    protected $supportedOptions = [
-        'element' => ['', 'The name of the element', 'string', true],
-        'errorMessage' => ['', 'The error message', 'array', true],
-        'minimum' => ['', 'The minimum value', 'integer', true],
-        'maximum' => ['', 'The maximum value', 'integer', false],
-    ];
-
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_length';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        $length = $this->charsetConverter->strlen('utf-8', $value);
-        if ($length < (int)$this->options['minimum']) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1441999425
-            );
-            return;
-        }
-        if (
-            !isset($this->options['maximum'])
-            || $this->options['maximum'] === ''
-        ) {
-            $this->options['maximum'] = null;
-        }
-        if (
-            $this->options['maximum'] !== null
-            && $length > (int)$this->options['maximum']
-        ) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1441999425
-            );
-        }
-    }
-
-    /**
-     * Get the local language label(s) for the message
-     * Overrides the abstract
-     *
-     * @param string $type The type
-     * @return string The local language message label
-     * @see \TYPO3\CMS\Form\Validation\AbstractValidator::_getLocalLanguageLabel()
-     */
-    public function getLocalLanguageLabel($type = '')
-    {
-        $label = static::LOCALISATION_OBJECT_NAME . '.' . $type;
-        $messages[] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label, 'form');
-        if ($this->options['maximum'] !== null) {
-            $messages[] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($label . 2, 'form');
-        }
-        $message = implode(', ', $messages);
-        return $message;
-    }
-
-    /**
-     * Substitute makers in the message text
-     * Overrides the abstract
-     *
-     * @param string $message Message text with markers
-     * @return string Message text with substituted markers
-     */
-    public function substituteMarkers($message)
-    {
-        return str_replace(
-            ['%minimum', '%maximum'],
-            [$this->options['minimum'], $this->options['maximum']],
-            $message
-        );
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/LessThanValidator.php b/typo3/sysext/form/Classes/Domain/Validator/LessThanValidator.php
deleted file mode 100644
index 5c5466cabf3b2feeec2062d8cd86964c61175ad5..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/LessThanValidator.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class LessThanValidator extends AbstractValidator
-{
-    /**
-     * @var array
-     */
-    protected $supportedOptions = [
-        'element' => ['', 'The name of the element', 'string', true],
-        'errorMessage' => ['', 'The error message', 'array', true],
-        'maximum' => ['', 'The maximum value', 'integer', true],
-    ];
-
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_lessthan';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        if ($value >= $this->options['maximum'] || !is_numeric($value)) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1441997981
-            );
-        }
-    }
-
-    /**
-     * Substitute makers in the message text
-     * Overrides the abstract
-     *
-     * @param string $message Message text with markers
-     * @return string Message text with substituted markers
-     */
-    public function substituteMarkers($message)
-    {
-        $message = str_replace('%maximum', $this->options['maximum'], $message);
-        return $message;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/RegExpValidator.php b/typo3/sysext/form/Classes/Domain/Validator/RegExpValidator.php
deleted file mode 100644
index 09857bd17ab5064db85bc8dc83a6e5fcd9e36d28..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/RegExpValidator.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class RegExpValidator extends AbstractValidator
-{
-    /**
-     * @var array
-     */
-    protected $supportedOptions = [
-        'element' => ['', 'The name of the element', 'string', true],
-        'errorMessage' => ['', 'The error message', 'array', true],
-        'expression' => ['', 'The regular expression', 'string', true],
-    ];
-
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_regexp';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        if (!preg_match($this->options['expression'], $value)) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1441997233
-            );
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/RequiredValidator.php b/typo3/sysext/form/Classes/Domain/Validator/RequiredValidator.php
deleted file mode 100644
index e1c80eface7971c25ccefd133db978d8453f4b2f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/RequiredValidator.php
+++ /dev/null
@@ -1,102 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class RequiredValidator extends AbstractValidator
-{
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_required';
-
-    /**
-     * @var bool
-     */
-    protected $allFieldsAreEmpty = true;
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        if (is_array($value)) {
-            array_walk_recursive($value, function ($value, $key, $validator) {
-                if (!empty($value) || $value === '0' || $value === 0) {
-                    $validator->setAllFieldsAreEmpty(false);
-                }
-            },
-                $this
-            );
-            if ($this->getAllFieldsAreEmpty()) {
-                $this->addError(
-                    $this->renderMessage(
-                        $this->options['errorMessage'][0],
-                        $this->options['errorMessage'][1],
-                        'error'
-                    ),
-                    1441980673
-                );
-            }
-        } else {
-            if (
-                empty($value)
-                && $value !== 0
-                && $value !== '0'
-            ) {
-                $this->addError(
-                    $this->renderMessage(
-                        $this->options['errorMessage'][0],
-                        $this->options['errorMessage'][1],
-                        'error'
-                    ),
-                    144198067
-                );
-            }
-        }
-    }
-
-    /**
-     * A helper method for the array_walk_recursive callback in the
-     * function isValid().
-     * If the callback detect a empty value, the
-     * property allFieldsAreEmpty is set to TRUE.
-     *
-     * @param bool $allFieldsAreEmpty
-     * @return void
-     */
-    protected function setAllFieldsAreEmpty($allFieldsAreEmpty = true)
-    {
-        $this->allFieldsAreEmpty = $allFieldsAreEmpty;
-    }
-
-    /**
-     * A helper method for the array_walk_recursive callback in the
-     * function isValid().
-     * If the callback detect a empty value, the
-     * property allFieldsAreEmpty is set to TRUE.
-     *
-     * @return bool
-     */
-    protected function getAllFieldsAreEmpty()
-    {
-        return $this->allFieldsAreEmpty;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/UriValidator.php b/typo3/sysext/form/Classes/Domain/Validator/UriValidator.php
deleted file mode 100644
index 3d2505c0adcbd7746f5f1c4c357288e171983eda..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/UriValidator.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class UriValidator extends AbstractValidator
-{
-    /**
-     * Constant for localisation
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_system_validate_uri';
-
-    /**
-     * Check if $value is valid. If it is not valid, needs to add an error
-     * to result.
-     *
-     * @param mixed $value
-     * @return void
-     */
-    public function isValid($value)
-    {
-        if (!preg_match('/^(?#Protocol)(?:(?:ht|f)tp(?:s?)\\:\\/\\/|~\\/|\\/)?(?#Username:Password)(?:\\w+:\\w+@)?(?#Subdomains)(?:(?:[-\\w]+\\.)+(?#TopLevel Domains)(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|travel|[a-z]{2}))(?#Port)(?::[\\d]{1,5})?(?#Directories)(?:(?:(?:\\/(?:[-\\w~!$+|.,=]|%[a-f\\d]{2})+)+|\\/)+|\\?|#)?(?#Query)(?:(?:\\?(?:[-\\w~!$+|.,*:]|%[a-f\\d{2}])+=?(?:[-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)(?:&(?:[-\\w~!$+|.,*:]|%[a-f\\d{2}])+=?(?:[-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)*)*(?#Anchor)(?:#(?:[-\\w~!$+|.,*:=]|%[a-f\\d]{2})*)?$/', $value)) {
-            $this->addError(
-                $this->renderMessage(
-                    $this->options['errorMessage'][0],
-                    $this->options['errorMessage'][1],
-                    'error'
-                ),
-                1441997233
-            );
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Domain/Validator/ValidationElementValidator.php b/typo3/sysext/form/Classes/Domain/Validator/ValidationElementValidator.php
deleted file mode 100644
index 81d1ca20b7b6a1b05bcea7cdd6025ebafa06ebbf..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Domain/Validator/ValidationElementValidator.php
+++ /dev/null
@@ -1,257 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Domain\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface;
-
-/**
- * A generic object validator which allows for specifying property validators
- */
-class ValidationElementValidator extends \TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator implements \TYPO3\CMS\Extbase\Validation\Validator\ObjectValidatorInterface
-{
-    /**
-     * @var \SplObjectStorage[]
-     */
-    protected $propertyValidators = [];
-
-    /**
-     * @var \TYPO3\CMS\Form\Utility\SessionUtility
-     */
-    protected $sessionUtility;
-
-    /**
-     * @param \TYPO3\CMS\Form\Utility\SessionUtility $sessionUtility
-     */
-    public function injectSessionUtility(\TYPO3\CMS\Form\Utility\SessionUtility $sessionUtility)
-    {
-        $this->sessionUtility = $sessionUtility;
-    }
-
-    /**
-     * Checks if the given value is valid according to the validator, and returns
-     * the Error Messages object which occurred.
-     *
-     * @param mixed $value The value that should be validated
-     * @return \TYPO3\CMS\Extbase\Error\Result
-     * @api
-     */
-    public function validate($value)
-    {
-        $this->result = new \TYPO3\CMS\Extbase\Error\Result();
-        if ($this->acceptsEmptyValues === false || $this->isEmpty($value) === false) {
-            if (!is_object($value)) {
-                $this->addError('Object expected, %1$s given.', 1241099149, [gettype($value)]);
-            } elseif ($this->isValidatedAlready($value) === false) {
-                $this->isValid($value);
-            }
-        }
-
-        return $this->result;
-    }
-
-    /**
-     * Load the property value to be used for validation.
-     *
-     * In case the object is a doctrine proxy, we need to load the real instance first.
-     *
-     * @param \TYPO3\CMS\Form\Domain\Model\ValidationElement $validationElement
-     * @param string $propertyName
-     * @return mixed
-     */
-    protected function getPropertyValue(\TYPO3\CMS\Form\Domain\Model\ValidationElement $validationElement, $propertyName)
-    {
-        /**
-         * If a confirmation page is set and a fileupload was done before
-         * there is no incoming data if the process action is called.
-         * The data is only in the session at this time.
-         * This results in a negative validation (if a validation is set).
-         * Therefore, look first in the session.
-         */
-        if ($this->sessionUtility->getSessionData($propertyName)) {
-            $propertyValue = $this->sessionUtility->getSessionData($propertyName);
-        } else {
-            $propertyValue = $validationElement->getIncomingField($propertyName);
-        }
-        return $propertyValue;
-    }
-
-    /**
-     * Checks if the specified property of the given object is valid, and adds
-     * found errors to the $messages object.
-     *
-     * @param mixed $value The value to be validated
-     * @param \Traversable $validators The validators to be called on the value
-     * @param string $propertyName Name of ther property to check
-     * @return void
-     */
-    protected function checkProperty($value, $validators, $propertyName)
-    {
-        /** @var \TYPO3\CMS\Extbase\Error\Result $result */
-        $result = null;
-        foreach ($validators as $validator) {
-            if ($validator instanceof ObjectValidatorInterface) {
-                $validator->setValidatedInstancesContainer($this->validatedInstancesContainer);
-            }
-
-            /**
-             * File upload validation.
-             *
-             * If a $_FILES array is found in the request data,
-             * iterate over all requested files and validate each
-             * single file.
-             */
-            if (
-                isset($value[0]['name'])
-                && isset($value[0]['type'])
-                && isset($value[0]['tmp_name'])
-                && isset($value[0]['size'])
-            ) {
-                foreach ($value as $file) {
-                    $currentResult = $validator->validate($file);
-                    if ($currentResult->hasMessages()) {
-                        if ($result == null) {
-                            $result = $currentResult;
-                        } else {
-                            $result->merge($currentResult);
-                        }
-                    }
-                }
-            } else {
-                $currentResult = $validator->validate($value);
-                if ($currentResult->hasMessages()) {
-                    if ($result == null) {
-                        $result = $currentResult;
-                    } else {
-                        $result->merge($currentResult);
-                    }
-                }
-            }
-        }
-        if ($result != null) {
-            $this->result->forProperty($propertyName)->merge($result);
-        }
-    }
-
-    /**
-     * Checks if the given value is valid according to the property validators.
-     *
-     * @param mixed $object The value that should be validated
-     * @return void
-     * @api
-     */
-    protected function isValid($object)
-    {
-        foreach ($this->propertyValidators as $propertyName => $validators) {
-            $propertyValue = $this->getPropertyValue($object, $propertyName);
-            $this->checkProperty($propertyValue, $validators, $propertyName);
-        }
-    }
-
-    /**
-     * Checks the given object can be validated by the validator implementation
-     *
-     * @param mixed $object The object to be checked
-     * @return bool TRUE if the given value can be validated
-     * @api
-     */
-    public function canValidate($object)
-    {
-        if (
-            is_object($object)
-            && $object instanceof \TYPO3\CMS\Form\Domain\Model\ValidationElement
-        ) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Adds the given validator for validation of the specified property.
-     *
-     * @param string $propertyName Name of the property to validate
-     * @param ValidatorInterface $validator The property validator
-     * @return void
-     * @api
-     */
-    public function addPropertyValidator($propertyName, ValidatorInterface $validator)
-    {
-        if (!isset($this->propertyValidators[$propertyName])) {
-            $this->propertyValidators[$propertyName] = new \SplObjectStorage();
-        }
-        $this->propertyValidators[$propertyName]->attach($validator);
-    }
-
-    /**
-     * @param object $object
-     * @return bool
-     */
-    protected function isValidatedAlready($object)
-    {
-        if ($this->validatedInstancesContainer === null) {
-            $this->validatedInstancesContainer = new \SplObjectStorage();
-        }
-        if ($this->validatedInstancesContainer->contains($object)) {
-            return true;
-        } else {
-            $this->validatedInstancesContainer->attach($object);
-
-            return false;
-        }
-    }
-
-    /**
-     * Returns all property validators - or only validators of the specified property
-     *
-     * @param string $propertyName Name of the property to return validators for
-     * @return array An array of validators
-     */
-    public function getPropertyValidators($propertyName = null)
-    {
-        if ($propertyName !== null) {
-            return (isset($this->propertyValidators[$propertyName])) ? $this->propertyValidators[$propertyName] : [];
-        } else {
-            return $this->propertyValidators;
-        }
-    }
-
-    /**
-     * @return int
-     */
-    public function countPropertyValidators()
-    {
-        $count = 0;
-        foreach ($this->propertyValidators as $propertyValidators) {
-            $count += $propertyValidators->count();
-        }
-        return $count;
-    }
-
-    /**
-     * @var \SplObjectStorage
-     */
-    protected $validatedInstancesContainer;
-
-    /**
-     * Allows to set a container to keep track of validated instances.
-     *
-     * @param \SplObjectStorage $validatedInstancesContainer A container to keep track of validated instances
-     * @return void
-     * @api
-     */
-    public function setValidatedInstancesContainer(\SplObjectStorage $validatedInstancesContainer)
-    {
-        $this->validatedInstancesContainer = $validatedInstancesContainer;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Exception.php b/typo3/sysext/form/Classes/Exception.php
new file mode 100644
index 0000000000000000000000000000000000000000..bd686473e717dcbc9888617b8930164313300304
--- /dev/null
+++ b/typo3/sysext/form/Classes/Exception.php
@@ -0,0 +1,25 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * A generic Form Exception
+ *
+ * @api
+ */
+class Exception extends \Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Hooks/DataStructureIdentifierHook.php b/typo3/sysext/form/Classes/Hooks/DataStructureIdentifierHook.php
new file mode 100644
index 0000000000000000000000000000000000000000..eefae9dbf731afbfa3626e07d61798e0d4798580
--- /dev/null
+++ b/typo3/sysext/form/Classes/Hooks/DataStructureIdentifierHook.php
@@ -0,0 +1,249 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Hooks;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\ArrayUtility as CoreArrayUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\Utility\ArrayUtility as ExtbaseArrayUtility;
+use TYPO3\CMS\Form\Domain\Configuration\ConfigurationService;
+use TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface;
+use TYPO3\CMS\Form\Service\TranslationService;
+
+/**
+ * Hooks into flex form handling of backend for tt_content form elements:
+ *
+ * * Adds existing forms to flex form drop down list
+ * * Adds finisher settings if "override finishers" is active
+ *
+ * Scope: backend
+ * @internal
+ */
+class DataStructureIdentifierHook
+{
+
+    /**
+     * The data structure depends on a current form selection (persistenceIdentifier)
+     * and if the field "overrideFinishers" is active. Add both to the identifier to
+     * hand these information over to parseDataStructureByIdentifierPostProcess() hook.
+     *
+     * @param array $fieldTca Incoming field TCA
+     * @param string $tableName Handled table
+     * @param string $fieldName Handled field
+     * @param array $row Current data row
+     * @param array $identifier Already calculated identifier
+     * @return array Modified identifier
+     */
+    public function getDataStructureIdentifierPostProcess(
+        array $fieldTca,
+        string $tableName,
+        string $fieldName,
+        array $row,
+        array $identifier
+    ): array {
+        if ($tableName === 'tt_content' && $fieldName === 'pi_flexform' && $row['CType'] === 'form_formframework') {
+            $currentFlexData = [];
+            if (!is_array($row['pi_flexform']) && !empty($row['pi_flexform'])) {
+                $currentFlexData = GeneralUtility::xml2array($row['pi_flexform']);
+            }
+
+            // Add selected form value
+            $identifier['ext-form-persistenceIdentifier'] = '';
+            if (!empty($currentFlexData['data']['sDEF']['lDEF']['settings.persistenceIdentifier']['vDEF'])) {
+                $identifier['ext-form-persistenceIdentifier'] = $currentFlexData['data']['sDEF']['lDEF']['settings.persistenceIdentifier']['vDEF'];
+            }
+
+            // Add bool - finisher override active or not
+            $identifier['ext-form-overrideFinishers'] = false;
+            if (
+                isset($currentFlexData['data']['sDEF']['lDEF']['settings.overrideFinishers']['vDEF'])
+                && (int)$currentFlexData['data']['sDEF']['lDEF']['settings.overrideFinishers']['vDEF'] === 1
+            ) {
+                $identifier['ext-form-overrideFinishers'] = true;
+            }
+        }
+        return $identifier;
+    }
+
+    /**
+     * Returns a modified flexform data array.
+     *
+     * This adds the list of existing form definitions to the form selection drop down
+     * and adds sheets to override finisher settings if requested.
+     *
+     * @param array $dataStructure
+     * @param array $identifier
+     * @return array
+     */
+    public function parseDataStructureByIdentifierPostProcess(array $dataStructure, array $identifier): array
+    {
+        if (isset($identifier['ext-form-persistenceIdentifier'])) {
+            // Add list of existing forms to drop down if we find our key in the identifier
+            $formPersistenceManager = GeneralUtility::makeInstance(ObjectManager::class)->get(FormPersistenceManagerInterface::class);
+            foreach ($formPersistenceManager->listForms() as $form) {
+                $dataStructure['sheets']['sDEF']['ROOT']['el']['settings.persistenceIdentifier']['TCEforms']['config']['items'][] = [
+                    $form['name'] . ' (' . $form['persistenceIdentifier'] . ')',
+                    $form['persistenceIdentifier'],
+                ];
+            }
+
+            // If a specific form is selected and if finisher override is active, add finisher sheets
+            if (!empty($identifier['ext-form-persistenceIdentifier'])
+                && isset($identifier['ext-form-overrideFinishers'])
+                && $identifier['ext-form-overrideFinishers'] === true
+            ) {
+                $persistenceIdentifier = $identifier['ext-form-persistenceIdentifier'];
+                $formDefinition = $formPersistenceManager->load($persistenceIdentifier);
+                $newSheets = $this->getAdditionalFinisherSheets($persistenceIdentifier, $formDefinition);
+                CoreArrayUtility::mergeRecursiveWithOverrule(
+                    $dataStructure,
+                    $newSheets
+                );
+            }
+        }
+        return $dataStructure;
+    }
+
+    /**
+     * Returns additional flexform sheets with finisher fields
+     *
+     * @param string $persistenceIdentifier Current persistence identifier
+     * @param array $formDefinition The form definition
+     * @return array
+     */
+    protected function getAdditionalFinisherSheets(string $persistenceIdentifier, array $formDefinition): array
+    {
+        if (!isset($formDefinition['finishers']) || empty($formDefinition['finishers'])) {
+            return [];
+        }
+
+        $prototypeName = isset($formDefinition['prototypeName']) ? $formDefinition['prototypeName'] : 'standard';
+        $prototypeConfiguration = GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(ConfigurationService::class)
+            ->getPrototypeConfiguration($prototypeName);
+
+        if (!isset($prototypeConfiguration['finishersDefinition']) || empty($prototypeConfiguration['finishersDefinition'])) {
+            return [];
+        }
+
+        $formIdentifier = $formDefinition['identifier'];
+        $finishersDefinition = $prototypeConfiguration['finishersDefinition'];
+
+        $sheets = ['sheets' => []];
+        foreach ($formDefinition['finishers'] as $finisherValue) {
+            $finisherIdentifier = $finisherValue['identifier'];
+            if (!isset($finishersDefinition[$finisherIdentifier]['FormEngine']['elements'])) {
+                continue;
+            }
+            $sheetIdentifier = md5(
+                implode('', [
+                    $persistenceIdentifier,
+                    $prototypeName,
+                    $formIdentifier,
+                    $finisherIdentifier
+                ])
+            );
+
+            $translationFile = $finishersDefinition[$finisherIdentifier]['FormEngine']['translationFile'];
+            $finishersDefinition[$finisherIdentifier]['FormEngine'] = TranslationService::getInstance()->translateValuesRecursive(
+                $finishersDefinition[$finisherIdentifier]['FormEngine'],
+                $translationFile
+            );
+            $finisherLabel = $finishersDefinition[$finisherIdentifier]['FormEngine']['label'];
+            $sheet = $this->initializeNewSheetArray($sheetIdentifier, $finisherLabel);
+
+            $sheetElements = [];
+            foreach ($finisherValue['options'] as $optionKey => $optionValue) {
+                if (is_array($optionValue)) {
+                    $optionKey = $optionKey . '.' . $this->extractDottedPathToLastElement($finisherValue['options'][$optionKey]);
+                    $elementConfiguration = ExtbaseArrayUtility::getValueByPath($finishersDefinition[$finisherIdentifier]['FormEngine']['elements'], $optionKey);
+                    $optionValue = ExtbaseArrayUtility::getValueByPath($finisherValue['options'], $optionKey);
+                } else {
+                    $elementConfiguration = $finishersDefinition[$finisherIdentifier]['FormEngine']['elements'][$optionKey];
+                }
+
+                if (empty($elementConfiguration)) {
+                    continue;
+                }
+
+                if (empty($optionValue)) {
+                    $elementConfiguration['label'] .= ' (default: "[Empty]")';
+                } else {
+                    $elementConfiguration['label'] .= ' (default: "' . $optionValue . '")';
+                }
+                $elementConfiguration['config']['default'] = $optionValue;
+                $sheetElements['settings.finishers.' . $finisherIdentifier . '.' . $optionKey] = $elementConfiguration;
+            }
+
+            ksort($sheetElements);
+
+            $sheet[$sheetIdentifier]['ROOT']['el'] = $sheetElements;
+            CoreArrayUtility::mergeRecursiveWithOverrule($sheets['sheets'], $sheet);
+        }
+        if (empty($sheets['sheets'])) {
+            return [];
+        }
+
+        return $sheets;
+    }
+
+    /**
+     * Boilerplate XML array of a new sheet
+     *
+     * @param string $sheetIdentifier
+     * @param string $finisherName
+     * @throws \InvalidArgumentException
+     * @return array
+     */
+    protected function initializeNewSheetArray(string $sheetIdentifier, string $finisherName): array
+    {
+        if (empty($sheetIdentifier)) {
+            throw new \InvalidArgumentException('$sheetIdentifier must not be empty.', 1472060918);
+        }
+        if (empty($finisherName)) {
+            throw new \InvalidArgumentException('$finisherName must not be empty.', 1472060919);
+        }
+
+        return [
+            $sheetIdentifier => [
+                'ROOT' => [
+                    'TCEforms' => [
+                        'sheetTitle' => $finisherName,
+                    ],
+                    'type' => 'array',
+                    'el' => [],
+                ],
+            ],
+        ];
+    }
+
+    /**
+     * Recursive helper to implode a nested array to a dotted path notation
+     *
+     * @param array $array
+     * @return string
+     */
+    protected function extractDottedPathToLastElement(array $array): string
+    {
+        $dottedPath = key($array);
+        foreach ($array as $key => $value) {
+            if (is_array($value)) {
+                $dottedPath = $dottedPath . '.' . $this->extractDottedPathToLastElement($value);
+            }
+        }
+        return $dottedPath;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Hooks/HandleIncomingFormValues.php b/typo3/sysext/form/Classes/Hooks/HandleIncomingFormValues.php
deleted file mode 100644
index aeeeec1477a9c504eeb1852f16877efa42d8cf0a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Hooks/HandleIncomingFormValues.php
+++ /dev/null
@@ -1,205 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Hooks;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\SingletonInterface;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Form\Domain\Builder\FormBuilder;
-use TYPO3\CMS\Form\Domain\Model\Element;
-use TYPO3\CMS\Form\Domain\Model\ValidationElement;
-
-/**
- * Handle the incoming form data
- */
-class HandleIncomingFormValues implements SingletonInterface
-{
-    /**
-     * @var \TYPO3\CMS\Form\Utility\SessionUtility
-     */
-    protected $sessionUtility;
-
-    /**
-     * @param \TYPO3\CMS\Form\Utility\SessionUtility $sessionUtility
-     * @return void
-     */
-    public function injectSessionUtility(\TYPO3\CMS\Form\Utility\SessionUtility $sessionUtility)
-    {
-        $this->sessionUtility = $sessionUtility;
-    }
-
-    /**
-     * Handle the incoming form data
-     *
-     * @param Element $element The element
-     * @param ValidationElement $validationElement
-     * @param mixed $modelValue
-     * @param FormBuilder $formBuilder
-     * @return void
-     */
-    public function handleIncomingFormValues(Element $element, ValidationElement $validationElement, $modelValue, FormBuilder $formBuilder)
-    {
-        $elementName = $element->getName();
-
-        if ($element->getElementType() === 'CHECKBOX') {
-            $groupedElement = false;
-            if ($element->getParentElement()->getElementType() === 'CHECKBOXGROUP') {
-                $incomingName = $element->getParentElement()->getName();
-                $groupedElement = true;
-            } else {
-                $incomingName = $elementName;
-            }
-            $incomingData = $formBuilder->getIncomingData()->getIncomingField($incomingName);
-            $checked = false;
-            if (is_array($incomingData)) {
-                if (
-                    isset($incomingData[$elementName])
-                    && $incomingData[$elementName] !== ''
-                ) {
-                    $this->setAttribute($element, 'checked', 'checked');
-                    $checked = true;
-                } else {
-                    $this->setAttribute($element, 'checked', null);
-                }
-            } else {
-                if (
-                    (!empty($modelValue) && $incomingData === $modelValue)
-                    || $incomingData === $incomingName . '-' . $element->getElementCounter()
-                ) {
-                    $this->setAttribute($element, 'checked', 'checked');
-                    $checked = true;
-                } else {
-                    $this->setAttribute($element, 'checked', null);
-                }
-            }
-            if (
-                $groupedElement
-                && $checked
-            ) {
-                $element->getParentElement()->setAdditionalArgument('atLeastOneCheckedChildElement', true);
-            }
-        } elseif ($element->getElementType() === 'RADIO') {
-            $groupedElement = false;
-            if ($element->getParentElement()->getElementType() === 'RADIOGROUP') {
-                $incomingName = $element->getParentElement()->getName();
-                $groupedElement = true;
-            } else {
-                $incomingName = $elementName;
-            }
-            $checked = false;
-            $incomingData = $formBuilder->getIncomingData()->getIncomingField($incomingName);
-            if (
-                (!empty($modelValue) && $incomingData === $modelValue)
-                || $incomingData === $incomingName . '-' . $element->getElementCounter()
-            ) {
-                $this->setAttribute($element, 'checked', 'checked');
-                $checked = true;
-            } else {
-                $this->setAttribute($element, 'checked', null);
-            }
-            if (
-                $groupedElement
-                && $checked
-            ) {
-                $element->getParentElement()->setAdditionalArgument('atLeastOneCheckedChildElement', true);
-            }
-        } elseif ($element->getElementType() === 'OPTION') {
-            $modelValue = (string)($element->getAdditionalArgument('value') ?: $element->getElementCounter());
-            if ($element->getParentElement()->getElementType() === 'OPTGROUP') {
-                $parentName = $element->getParentElement()->getParentElement()->getName();
-            } else {
-                $parentName = $element->getParentElement()->getName();
-            }
-            $incomingData = $formBuilder->getIncomingData()->getIncomingField($parentName);
-
-            /* Multiselect */
-            if (is_array($incomingData)) {
-                if (in_array($modelValue, $incomingData, true)) {
-                    $element->setAdditionalArgument('selected', 'selected');
-                } else {
-                    $element->setAdditionalArgument('selected', null);
-                }
-            } else {
-                if ($modelValue === $incomingData) {
-                    $element->setAdditionalArgument('selected', 'selected');
-                } else {
-                    $element->setAdditionalArgument('selected', null);
-                }
-            }
-        } elseif ($element->getElementType() === 'TEXTAREA') {
-            $incomingData = $formBuilder->getIncomingData()->getIncomingField($elementName);
-            $element->setAdditionalArgument('text', $incomingData);
-        } elseif ($element->getElementType() === 'FILEUPLOAD') {
-            if (
-                $formBuilder->getValidationErrors() == null
-                || (
-                    $formBuilder->getValidationErrors()
-                    && $formBuilder->getValidationErrors()->forProperty($elementName)->hasErrors() !== true
-                )
-            ) {
-                $uploadedFiles = $formBuilder->getIncomingData()->getIncomingField($elementName);
-                if (is_array($uploadedFiles)) {
-                    foreach ($uploadedFiles as $key => &$file) {
-                        $tempFilename = $this->saveUploadedFile($file['tmp_name']);
-                        if (!$tempFilename) {
-                            unset($uploadedFiles[$key]);
-                            continue;
-                        }
-                        $file['tempFilename'] = $tempFilename;
-                    }
-                    $element->setAdditionalArgument('uploadedFiles', $uploadedFiles);
-                    $this->setAttribute($element, 'value', '');
-                    $this->sessionUtility->setSessionData($elementName, $uploadedFiles);
-                }
-            }
-        }
-    }
-
-    /**
-     * Save a uploaded file
-     *
-     * @param string $uploadedFile
-     * @return NULL|string
-     */
-    public function saveUploadedFile($uploadedFile)
-    {
-        if (is_uploaded_file($uploadedFile)) {
-            $tempFilename = GeneralUtility::upload_to_tempfile($uploadedFile);
-            if (TYPO3_OS === 'WIN') {
-                $tempFilename = GeneralUtility::fixWindowsFilePath($tempFilename);
-            }
-            if ($tempFilename !== '') {
-                return $tempFilename;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Set the value Attribute to the right place
-     *
-     * @param Element $element The element
-     * @param string $key
-     * @param string $value
-     * @return void
-     */
-    public function setAttribute(Element $element, $key, $value = '')
-    {
-        if ($element->getHtmlAttribute($key) !== null) {
-            $element->setHtmlAttribute($key, $value);
-        } else {
-            $element->setAdditionalArgument($key, $value);
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Hooks/PageLayoutView/MailformPreviewRenderer.php b/typo3/sysext/form/Classes/Hooks/PageLayoutView/MailformPreviewRenderer.php
deleted file mode 100644
index 5a5b3f8818fd70d99337114eceaff4f42cf542b8..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Hooks/PageLayoutView/MailformPreviewRenderer.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Hooks\PageLayoutView;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Contains a preview rendering for the page module of
- * CType="mailform"
- */
-class MailformPreviewRenderer implements \TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHookInterface
-{
-    /**
-     * Preprocesses the preview rendering of a content element of type "mailform"
-     *
-     * @param \TYPO3\CMS\Backend\View\PageLayoutView $parentObject Calling parent object
-     * @param bool $drawItem Whether to draw the item using the default functionality
-     * @param string $headerContent Header content
-     * @param string $itemContent Item content
-     * @param array $row Record row of tt_content
-     *
-     * @return void
-     */
-    public function preProcess(\TYPO3\CMS\Backend\View\PageLayoutView &$parentObject, &$drawItem, &$headerContent, &$itemContent, array &$row)
-    {
-        if ($row['CType'] === 'mailform') {
-            $contentType = $parentObject->CType_labels[$row['CType']];
-            $itemContent = $parentObject->linkEditContent('<strong>' . htmlspecialchars($contentType) . '</strong>', $row) . '<br />';
-            $drawItem = false;
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Hooks/SoftReferenceParserHook.php b/typo3/sysext/form/Classes/Hooks/SoftReferenceParserHook.php
new file mode 100644
index 0000000000000000000000000000000000000000..17d22b1c89dd42d62b90440737900020e3721a16
--- /dev/null
+++ b/typo3/sysext/form/Classes/Hooks/SoftReferenceParserHook.php
@@ -0,0 +1,60 @@
+<?php
+namespace TYPO3\CMS\Form\Hooks;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Database\SoftReferenceIndex;
+
+/**
+ * Register new referenced formDefinitions within a plugin as a soft reference.
+ *
+ * This is used in BE to track how often a specific form is used in a content
+ * element. The number is shown in the form module "Manage forms".
+ *
+ * Scope: backend
+ * @internal
+ */
+class SoftReferenceParserHook extends SoftReferenceIndex
+{
+    /**
+     * Main function through which all processing happens
+     *
+     * @param string $table Database table name
+     * @param string $field Field name for which processing occurs
+     * @param int $uid UID of the record
+     * @param string $content The content/value of the field
+     * @param string $spKey The softlink parser key. This is only interesting if more than one parser is grouped in the same class. That is the case with this parser.
+     * @param array $spParams Parameters of the softlink parser. Basically this is the content inside optional []-brackets after the softref keys. Parameters are exploded by ";
+     * @param string $structurePath If running from inside a FlexForm structure, this is the path of the tag.
+     * @return array Result array on positive matches, see description above. Otherwise FALSE
+     */
+    public function findRef($table, $field, $uid, $content, $spKey, $spParams, $structurePath = '')
+    {
+        $this->tokenID_basePrefix = $table . ':' . $uid . ':' . $field . ':' . $structurePath . ':' . $spKey;
+        $tokenId = $this->makeTokenID($content);
+        return [
+            'content' => '{softref:' . $tokenId . '}',
+            'elements' => [
+                $tokenId => [
+                    'matchString' => $content,
+                    'subst' => [
+                        'type' => 'string',
+                        'tokenID' => $tokenId,
+                        'tokenValue' => $content
+                    ],
+                ]
+            ]
+        ];
+    }
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Configuration/ConfigurationManager.php b/typo3/sysext/form/Classes/Mvc/Configuration/ConfigurationManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..3bb82c2b40ebb9b24f2aac3f2e62a1982d4b02b5
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Configuration/ConfigurationManager.php
@@ -0,0 +1,146 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Configuration;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\ArrayUtility as CoreArrayUtility;
+use TYPO3\CMS\Extbase\Configuration\ConfigurationManager as ExtbaseConfigurationManager;
+use TYPO3\CMS\Form\Mvc\Configuration\Exception\ExtensionNameRequiredException;
+use TYPO3\CMS\Form\Utility\ArrayUtility;
+
+/**
+ * Extend the ExtbaseConfigurationManager to read YAML configurations.
+ *
+ * Scope: frontend / backend
+ * @internal
+ */
+class ConfigurationManager extends ExtbaseConfigurationManager implements ConfigurationManagerInterface
+{
+    /**
+     * @var \TYPO3\CMS\Form\Mvc\Configuration\YamlSource
+     */
+    protected $yamlSource;
+
+    /**
+     * 1st level configuration cache
+     *
+     * @var array
+     */
+    protected $configurationCache = [];
+
+    /**
+     * @param \TYPO3\CMS\Form\Mvc\Configuration\YamlSource $yamlSource
+     * @internal
+     */
+    public function injectYamlSource(\TYPO3\CMS\Form\Mvc\Configuration\YamlSource $yamlSource)
+    {
+        $this->yamlSource = $yamlSource;
+    }
+
+    /**
+     * @param string $configurationType The kind of configuration to fetch - must be one of the CONFIGURATION_TYPE_* constants
+     * @param string $extensionName if specified, the configuration for the given extension will be returned.
+     * @param string $pluginName if specified, the configuration for the given plugin will be returned.
+     * @return array The configuration
+     * @internal
+     */
+    public function getConfiguration($configurationType, $extensionName = null, $pluginName = null)
+    {
+        switch ($configurationType) {
+            case self::CONFIGURATION_TYPE_YAML_SETTINGS:
+                return $this->getConfigurationFromYamlFile($extensionName);
+            default:
+                return parent::getConfiguration($configurationType, $extensionName, $pluginName);
+        }
+    }
+
+    /**
+     * Load and parse yaml files which are configured within the TypoScript
+     * path plugin.tx_extensionkey.settings.yamlConfigurations
+     *
+     * The following steps will be done:
+     *
+     * * Convert each singe yaml file into an array
+     * * merge this arrays together
+     * * resolve all declared inheritances
+     * * remove all keys if their values are NULL
+     * * return all configuration paths within TYPO3.CMS
+     * * sort by array keys, if all keys within the current nesting level are numerical keys
+     * * resolve possible TypoScript settings in FE mode
+     *
+     * @param string $extensionName
+     * @return array
+     * @throws ExtensionNameRequiredException
+     */
+    protected function getConfigurationFromYamlFile(string $extensionName): array
+    {
+        if (empty($extensionName)) {
+            throw new ExtensionNameRequiredException(
+                'Please specify an extension key to load a YAML configuration',
+                1471473377
+            );
+        }
+        $ucFirstExtensioName = ucfirst($extensionName);
+
+        // 1st level cache
+        $configurationCacheKey = strtolower(self::CONFIGURATION_TYPE_YAML_SETTINGS . '|' . $extensionName);
+        if (isset($this->configurationCache[$configurationCacheKey])) {
+            return $this->configurationCache[$configurationCacheKey];
+        }
+
+        $typoscriptSettings = parent::getConfiguration(
+            ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS,
+            $extensionName
+        );
+        $yamlSettingsFilePaths = isset($typoscriptSettings['yamlConfigurations'])
+            ? $typoscriptSettings['yamlConfigurations']
+            : [];
+        $yamlSettings = InheritancesResolverService::create($this->yamlSource->load($yamlSettingsFilePaths))
+            ->getResolvedConfiguration();
+
+        $yamlSettings = ArrayUtility::removeNullValuesRecursive($yamlSettings);
+        $yamlSettings = is_array($yamlSettings['TYPO3']['CMS'][$ucFirstExtensioName])
+            ? $yamlSettings['TYPO3']['CMS'][$ucFirstExtensioName]
+            : [];
+        $yamlSettings = ArrayUtility::sortNumericArrayKeysRecursive($yamlSettings);
+        $yamlSettings = $this->overrideConfigurationByTypoScript($yamlSettings, $extensionName);
+
+        // 1st level cache
+        $this->configurationCache[$configurationCacheKey] = $yamlSettings;
+        return $yamlSettings;
+    }
+
+    /**
+     * @param array $yamlSettings
+     * @param string $extensionName
+     * @return array
+     */
+    protected function overrideConfigurationByTypoScript(array $yamlSettings, string $extensionName): array
+    {
+        $typoScript = parent::getConfiguration(self::CONFIGURATION_TYPE_SETTINGS, $extensionName);
+        if (is_array($typoScript['yamlSettingsOverrides']) && !empty($typoScript['yamlSettingsOverrides'])) {
+            CoreArrayUtility::mergeRecursiveWithOverrule(
+                $yamlSettings,
+                $typoScript['yamlSettingsOverrides']
+            );
+
+            if ($this->environmentService->isEnvironmentInFrontendMode()) {
+                $yamlSettings = $this->objectManager->get(TypoScriptService::class)
+                    ->resolvePossibleTypoScriptConfiguration($yamlSettings);
+            }
+        }
+        return $yamlSettings;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Configuration/ConfigurationManagerInterface.php b/typo3/sysext/form/Classes/Mvc/Configuration/ConfigurationManagerInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..0fd7c3b71278babeae48f906b05979cb42a2beae
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Configuration/ConfigurationManagerInterface.php
@@ -0,0 +1,29 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Configuration;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface as ExtbaseConfigurationManagerInterface;
+
+/**
+ * Class ConfigurationManagerInterface
+ *
+ * Scope: frontend / backend
+ * @internal
+ */
+interface ConfigurationManagerInterface extends ExtbaseConfigurationManagerInterface
+{
+    const CONFIGURATION_TYPE_YAML_SETTINGS = 'YamlSettings';
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Configuration/Exception.php b/typo3/sysext/form/Classes/Mvc/Configuration/Exception.php
new file mode 100644
index 0000000000000000000000000000000000000000..5aa153b8a1389afe7a41ca8e4be872d040186616
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Configuration/Exception.php
@@ -0,0 +1,27 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Configuration;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Exception as FormException;
+
+/**
+ * A generic Form configuration Exception
+ *
+ * @internal
+ */
+class Exception extends FormException
+{
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Configuration/Exception/CycleInheritancesException.php b/typo3/sysext/form/Classes/Mvc/Configuration/Exception/CycleInheritancesException.php
new file mode 100644
index 0000000000000000000000000000000000000000..d2d832aaf9535670d0232eda91ee1b5f440a7c18
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Configuration/Exception/CycleInheritancesException.php
@@ -0,0 +1,28 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Configuration\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Mvc\Configuration\Exception;
+
+/**
+ * This exception is thrown if the InheritancesResolverService wants to
+ * solve declared inheritances which point cyclically to themselves.
+ *
+ * @internal
+ */
+class CycleInheritancesException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Configuration/Exception/ExtensionNameRequiredException.php b/typo3/sysext/form/Classes/Mvc/Configuration/Exception/ExtensionNameRequiredException.php
new file mode 100644
index 0000000000000000000000000000000000000000..e125e67209481d4b2b4fad9b69162bbd2ca63148
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Configuration/Exception/ExtensionNameRequiredException.php
@@ -0,0 +1,28 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Configuration\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Mvc\Configuration\Exception;
+
+/**
+ * This exception is thrown if the configuration manager wants to load
+ * a YAML file from an empty extension key
+ *
+ * @internal
+ */
+class ExtensionNameRequiredException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Configuration/Exception/NoSuchFileException.php b/typo3/sysext/form/Classes/Mvc/Configuration/Exception/NoSuchFileException.php
new file mode 100644
index 0000000000000000000000000000000000000000..c616ce3354c5d58e76fbb50f2b97271c3c149af9
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Configuration/Exception/NoSuchFileException.php
@@ -0,0 +1,24 @@
+<?php
+namespace TYPO3\CMS\Form\Mvc\Configuration\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Mvc\Configuration\Exception;
+
+/**
+ * A No Such File exception
+ */
+class NoSuchFileException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Configuration/Exception/ParseErrorException.php b/typo3/sysext/form/Classes/Mvc/Configuration/Exception/ParseErrorException.php
new file mode 100644
index 0000000000000000000000000000000000000000..47682656c1186325ba2f7356bd1359cf488e32a3
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Configuration/Exception/ParseErrorException.php
@@ -0,0 +1,24 @@
+<?php
+namespace TYPO3\CMS\Form\Mvc\Configuration\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Mvc\Configuration\Exception;
+
+/**
+ * A Parse Error exception
+ */
+class ParseErrorException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Configuration/InheritancesResolverService.php b/typo3/sysext/form/Classes/Mvc/Configuration/InheritancesResolverService.php
new file mode 100644
index 0000000000000000000000000000000000000000..26f13ec540f389bc70317cc8c21e31410ba04193
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Configuration/InheritancesResolverService.php
@@ -0,0 +1,375 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Configuration;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\Utility\ArrayUtility;
+use TYPO3\CMS\Form\Mvc\Configuration\Exception\CycleInheritancesException;
+
+/**
+ * Resolve declared inheritances within an configuration array
+ *
+ * Scope: frontend / backend
+ * @internal
+ */
+class InheritancesResolverService
+{
+
+    /**
+     * The operator which is used to declare inheritances
+     */
+    const INHERITANCE_OPERATOR = '__inheritances';
+
+    /**
+     * The reference configuration is used to get untouched values which
+     * can be merged into the touched configuration.
+     *
+     * @var array
+     */
+    protected $referenceConfiguration = [];
+
+    /**
+     * This stack is needed to find cyclically inheritances which are on
+     * the same nesting level but which do not follow each other directly.
+     *
+     * @var array
+     */
+    protected $inheritanceStack = [];
+
+    /**
+     * Needed to park a configuration path for cyclically inheritances
+     * detection while inheritances for this path is ongoing.
+     *
+     * @var string
+     */
+    protected $inheritancePathToCkeck = '';
+
+    /**
+     * Returns an instance of this service. Additionally the configuration
+     * which should be resolved can be passed.
+     *
+     * @param array $configuration
+     * @return InheritancesResolverService
+     * @internal
+     */
+    public static function create(array $configuration = []): InheritancesResolverService
+    {
+        /** @var InheritancesResolverService $inheritancesResolverService */
+        $inheritancesResolverService = GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(self::class);
+        $inheritancesResolverService->setReferenceConfiguration($configuration);
+        return $inheritancesResolverService;
+    }
+
+    /**
+     * Reset the state of this service.
+     * Mainly introduced for unit tests.
+     *
+     * @return InheritancesResolverService
+     * @internal
+     */
+    public function reset()
+    {
+        $this->referenceConfiguration = [];
+        $this->inheritanceStack = [];
+        $this->inheritancePathToCkeck = '';
+        return $this;
+    }
+
+    /**
+     * Set the reference configuration which is used to get untouched
+     * values which can be merged into the touched configuration.
+     *
+     * @param array
+     * @return InheritancesResolverService
+     */
+    public function setReferenceConfiguration(array $referenceConfiguration)
+    {
+        $this->referenceConfiguration = $referenceConfiguration;
+        return $this;
+    }
+
+    /**
+     * Resolve all inheritances within a configuration.
+     * After that the configuration array is cleaned from the
+     * inheritance operator.
+     *
+     * @return array
+     * @internal
+     */
+    public function getResolvedConfiguration(): array
+    {
+        $configuration = $this->resolve($this->referenceConfiguration);
+        $configuration = $this->removeInheritanceOperatorRecursive($configuration);
+        return $configuration;
+    }
+
+    /**
+     * Resolve all inheritances within a configuration.
+     *
+     * @toDo: More description
+     * @param array $configuration
+     * @param array $pathStack
+     * @param bool $setInheritancePathToCkeck
+     * @return array
+     */
+    protected function resolve(
+        array $configuration,
+        array $pathStack = [],
+        bool $setInheritancePathToCkeck = true
+    ): array {
+        foreach ($configuration as $key => $values) {
+            $pathStack[] = $key;
+            $path = implode('.', $pathStack);
+
+            $this->throwExceptionIfCycleInheritances($path, $path);
+            if ($setInheritancePathToCkeck) {
+                $this->inheritancePathToCkeck = $path;
+            }
+
+            if (is_array($configuration[$key])) {
+                if (isset($configuration[$key][self::INHERITANCE_OPERATOR])) {
+                    $inheritances = ArrayUtility::getValueByPath(
+                        $this->referenceConfiguration,
+                        $path . '.' . self::INHERITANCE_OPERATOR
+                    );
+
+                    if (is_array($inheritances)) {
+                        $inheritedConfigurations = $this->resolveInheritancesRecursive($inheritances);
+
+                        $configuration[$key] = $this->mergeRecursiveWithOverrule(
+                            $inheritedConfigurations,
+                            $configuration[$key]
+                        );
+                    }
+
+                    unset($configuration[$key][self::INHERITANCE_OPERATOR]);
+                }
+
+                if (!empty($configuration[$key])) {
+                    $configuration[$key] = $this->resolve(
+                        $configuration[$key],
+                        $pathStack
+                    );
+                }
+            }
+            array_pop($pathStack);
+        }
+
+        return $configuration;
+    }
+
+    /**
+     * Additional helper for the resolve method.
+     *
+     * @toDo: More description
+     * @param array $inheritances
+     * @return array
+     * @throws CycleInheritancesException
+     */
+    protected function resolveInheritancesRecursive(array $inheritances): array
+    {
+        ksort($inheritances);
+        $inheritedConfigurations = [];
+        foreach ($inheritances as $inheritancePath) {
+            $this->throwExceptionIfCycleInheritances($inheritancePath, $inheritancePath);
+            $inheritedConfiguration = ArrayUtility::getValueByPath(
+                $this->referenceConfiguration,
+                $inheritancePath
+            );
+
+            if (
+                isset($inheritedConfiguration[self::INHERITANCE_OPERATOR])
+                && count($inheritedConfiguration) === 1
+            ) {
+                if ($this->inheritancePathToCkeck === $inheritancePath) {
+                    throw new CycleInheritancesException(
+                        $this->inheritancePathToCkeck . ' has cycle inheritances',
+                        1474900796
+                    );
+                }
+
+                $inheritedConfiguration = $this->resolveInheritancesRecursive(
+                    $inheritedConfiguration[self::INHERITANCE_OPERATOR]
+                );
+            } else {
+                $pathStack = explode('.', $inheritancePath);
+                $key = array_pop($pathStack);
+                $newConfiguration = [
+                    $key => $inheritedConfiguration
+                ];
+                $inheritedConfiguration = $this->resolve(
+                    $newConfiguration,
+                    $pathStack,
+                    false
+                );
+                $inheritedConfiguration = $inheritedConfiguration[$key];
+            }
+
+            $inheritedConfigurations = $this->mergeRecursiveWithOverrule(
+                $inheritedConfigurations,
+                $inheritedConfiguration
+            );
+        }
+
+        return $inheritedConfigurations;
+    }
+
+    /**
+     * Throw an exception if a cycle is detected.
+     *
+     * @toDo: More description
+     * @param string $path
+     * @param string $pathToCheck
+     * @return void
+     * @throws CycleInheritancesException
+     */
+    protected function throwExceptionIfCycleInheritances(string $path, string $pathToCheck)
+    {
+        $configuration = ArrayUtility::getValueByPath(
+            $this->referenceConfiguration,
+            $path
+        );
+
+        if (isset($configuration[self::INHERITANCE_OPERATOR])) {
+            $inheritances = ArrayUtility::getValueByPath(
+                $this->referenceConfiguration,
+                $path . '.' . self::INHERITANCE_OPERATOR
+            );
+            if (is_array($inheritances)) {
+                foreach ($inheritances as $inheritancePath) {
+                    $configuration = ArrayUtility::getValueByPath(
+                        $this->referenceConfiguration,
+                        $inheritancePath
+                    );
+                    if (isset($configuration[self::INHERITANCE_OPERATOR])) {
+                        $_inheritances = ArrayUtility::getValueByPath(
+                            $this->referenceConfiguration,
+                            $inheritancePath . '.' . self::INHERITANCE_OPERATOR
+                        );
+                        foreach ($_inheritances as $_inheritancePath) {
+                            if (strpos($pathToCheck, $_inheritancePath) === 0) {
+                                throw new CycleInheritancesException(
+                                    $pathToCheck . ' has cycle inheritances',
+                                    1474900797
+                                );
+                            }
+                        }
+                    }
+
+                    if (
+                        is_array($this->inheritanceStack[$pathToCheck])
+                        && in_array($inheritancePath, $this->inheritanceStack[$pathToCheck])
+                    ) {
+                        $this->inheritanceStack[$pathToCheck][] = $inheritancePath;
+                        throw new CycleInheritancesException(
+                            $pathToCheck . ' has cycle inheritances',
+                            1474900799
+                        );
+                    }
+                    $this->inheritanceStack[$pathToCheck][] = $inheritancePath;
+                    $this->throwExceptionIfCycleInheritances($inheritancePath, $pathToCheck);
+                }
+                $this->inheritanceStack[$pathToCheck] = null;
+            }
+        }
+    }
+
+    /**
+     * Recursively remove self::INHERITANCE_OPERATOR keys
+     *
+     * @param array $array
+     * @return array the modified array
+     */
+    protected function removeInheritanceOperatorRecursive(array $array): array
+    {
+        $result = $array;
+        foreach ($result as $key => $value) {
+            if ($key === self::INHERITANCE_OPERATOR) {
+                unset($result[$key]);
+                continue;
+            }
+
+            if (is_array($value)) {
+                $result[$key] = $this->removeInheritanceOperatorRecursive($value);
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * Merges two arrays recursively and "binary safe" (integer keys are overridden as well),
+     * overruling similar values in the first array ($firstArray) with the
+     * values of the second array ($secondArray)
+     * In case of identical keys, ie. keeping the values of the second.
+     * This is basicly the Extbase arrayMergeRecursiveOverrule method.
+     * This method act different to the core mergeRecursiveWithOverrule method.
+     * This method has the possibility to overrule a array value within the
+     * $firstArray with a string value within the $secondArray.
+     * The core method does not support such a overrule.
+     * The reason for this code duplication is that the extbase method will be
+     * deprecated in the future.
+     *
+     * @param array $firstArray First array
+     * @param array $secondArray Second array, overruling the first array
+     * @param bool $dontAddNewKeys If set, keys that are NOT found in $firstArray (first array)
+     *                             will not be set. Thus only existing value can/will be
+     *                             overruled from second array.
+     * @param bool $emptyValuesOverride If set (which is the default), values from $secondArray
+     *                                  will overrule if they are empty (according to PHP's empty() function)
+     * @return array Resulting array where $secondArray values has overruled $firstArray values
+     * @internal
+     */
+    protected function mergeRecursiveWithOverrule(
+        array $firstArray,
+        array $secondArray,
+        bool $dontAddNewKeys = false,
+        bool $emptyValuesOverride = true
+    ): array {
+        foreach ($secondArray as $key => $value) {
+            if (
+                array_key_exists($key, $firstArray)
+                && is_array($firstArray[$key])
+            ) {
+                if (is_array($secondArray[$key])) {
+                    $firstArray[$key] = $this->mergeRecursiveWithOverrule(
+                        $firstArray[$key],
+                        $secondArray[$key],
+                        $dontAddNewKeys,
+                        $emptyValuesOverride
+                    );
+                } else {
+                    $firstArray[$key] = $secondArray[$key];
+                }
+            } else {
+                if ($dontAddNewKeys) {
+                    if (array_key_exists($key, $firstArray)) {
+                        if ($emptyValuesOverride || !empty($value)) {
+                            $firstArray[$key] = $value;
+                        }
+                    }
+                } else {
+                    if ($emptyValuesOverride || !empty($value)) {
+                        $firstArray[$key] = $value;
+                    }
+                }
+            }
+        }
+        reset($firstArray);
+        return $firstArray;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Configuration/TypoScriptService.php b/typo3/sysext/form/Classes/Mvc/Configuration/TypoScriptService.php
new file mode 100644
index 0000000000000000000000000000000000000000..2f48eb5ffd987f81fbb1855700bc97d8405ee187
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Configuration/TypoScriptService.php
@@ -0,0 +1,99 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Configuration;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+
+/**
+ * Utilities to manage and convert TypoScript
+ *
+ * Scope: frontend
+ */
+class TypoScriptService
+{
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Service\TypoScriptService
+     */
+    protected $extbaseTypoScriptService;
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Service\TypoScriptService $typoScriptService
+     * @internal
+     */
+    public function injectTypoScriptService(\TYPO3\CMS\Extbase\Service\TypoScriptService $typoScriptService)
+    {
+        $this->extbaseTypoScriptService = $typoScriptService;
+    }
+
+    /**
+     * Parse an configuration with ContentObjectRenderer::cObjGetSingle()
+     * and return the result.
+     *
+     * @param array $configuration
+     * @return array
+     * @internal
+     */
+    public function resolvePossibleTypoScriptConfiguration(array $configuration = []): array
+    {
+        $configuration = $this->extbaseTypoScriptService->convertPlainArrayToTypoScriptArray($configuration);
+        $configuration = $this->resolveTypoScriptConfiguration($configuration);
+        $configuration = $this->extbaseTypoScriptService->convertTypoScriptArrayToPlainArray($configuration);
+        return $configuration;
+    }
+
+    /**
+     * Parse an configuration with ContentObjectRenderer::cObjGetSingle()
+     * if there is an array key without and with a dot at the end.
+     * This sample would be identified as a TypoScript parsable configuration
+     * part:
+     *
+     * [
+     *   'example' => 'TEXT'
+     *   'example.' => [
+     *     'value' => 'some value'
+     *   ]
+     * ]
+     *
+     * @param array $configuration
+     * @return array
+     */
+    protected function resolveTypoScriptConfiguration(array $configuration = []): array
+    {
+        foreach ($configuration as $key => $value) {
+            $keyWithoutDot = rtrim((string)$key, '.');
+            if (isset($configuration[$keyWithoutDot]) && isset($configuration[$keyWithoutDot . '.'])) {
+                $value = $this->getTypoScriptFrontendController()->cObj->cObjGetSingle(
+                    $configuration[$keyWithoutDot],
+                    $configuration[$keyWithoutDot . '.']
+                );
+                $configuration[$keyWithoutDot] = $value;
+            } elseif (!isset($configuration[$keyWithoutDot]) && isset($configuration[$keyWithoutDot . '.'])) {
+                $configuration[$keyWithoutDot] = $this->resolveTypoScriptConfiguration($value);
+            }
+            unset($configuration[$keyWithoutDot . '.']);
+        }
+        return $configuration;
+    }
+
+    /**
+     * @return TypoScriptFrontendController
+     */
+    protected function getTypoScriptFrontendController()
+    {
+        return $GLOBALS['TSFE'];
+    }
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Configuration/YamlSource.php b/typo3/sysext/form/Classes/Mvc/Configuration/YamlSource.php
new file mode 100644
index 0000000000000000000000000000000000000000..d628a18bd9ab53c748617b455fb14d5904f96815
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Configuration/YamlSource.php
@@ -0,0 +1,156 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Configuration;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Symfony\Component\Yaml\Exception\ParseException;
+use Symfony\Component\Yaml\Yaml;
+use TYPO3\CMS\Core\Resource\File;
+use TYPO3\CMS\Core\Utility\ArrayUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Form\Mvc\Configuration\Exception\NoSuchFileException;
+use TYPO3\CMS\Form\Mvc\Configuration\Exception\ParseErrorException;
+use TYPO3\CMS\Form\Utility\ArrayUtility as FormArrayUtility;
+
+/**
+ * Configuration source based on YAML files
+ *
+ * Scope: frontend / backend
+ * @internal
+ */
+class YamlSource
+{
+    /**
+     * Will be set if the PHP YAML Extension is installed.
+     * Having this installed massively improves YAML parsing performance.
+     *
+     * @var bool
+     * @see http://pecl.php.net/package/yaml
+     */
+    protected $usePhpYamlExtension = false;
+
+    /**
+     * Use PHP YAML Extension if installed.
+     * @internal
+     */
+    public function __construct()
+    {
+        if (extension_loaded('yaml')) {
+            $this->usePhpYamlExtension = true;
+        }
+    }
+
+    /**
+     * Loads the specified configuration files and returns its merged content
+     * as an array.
+     *
+     * @param array $filesToLoad
+     * @return array
+     * @throws ParseErrorException
+     * @throws NoSuchFileException
+     * @internal
+     */
+    public function load(array $filesToLoad): array
+    {
+        $configuration = [];
+        foreach ($filesToLoad as $fileToLoad) {
+            if ($fileToLoad instanceof File) {
+                $fileIdentifier = $fileToLoad->getIdentifier();
+                $rawYamlContent = $fileToLoad->getContents();
+            } else {
+                $fileIdentifier = $fileToLoad;
+                $fileToLoad = GeneralUtility::getFileAbsFileName($fileToLoad);
+                if (is_file($fileToLoad)) {
+                    $rawYamlContent = file_get_contents($fileToLoad);
+                } else {
+                    throw new NoSuchFileException(
+                        'The file "' . $fileToLoad . '" does not exist.',
+                        1471473378
+                    );
+                }
+            }
+
+            try {
+                if ($this->usePhpYamlExtension) {
+                    $loadedConfiguration = @yaml_parse($rawYamlContent);
+                    if ($loadedConfiguration === false) {
+                        throw new ParseErrorException(
+                            'A parse error occurred while parsing file "' . $fileIdentifier . '".',
+                            1391894094
+                        );
+                    }
+                } else {
+                    $loadedConfiguration = Yaml::parse($rawYamlContent);
+                }
+
+                if (is_array($loadedConfiguration)) {
+                    ArrayUtility::mergeRecursiveWithOverrule($configuration, $loadedConfiguration);
+                }
+            } catch (ParseException $exception) {
+                throw new ParseErrorException(
+                    'A parse error occurred while parsing file "' . $fileIdentifier . '". Error message: ' . $exception->getMessage(),
+                    1480195405
+                );
+            }
+        }
+
+        $configuration = FormArrayUtility::convertBooleanStringsToBooleanRecursive($configuration);
+        return $configuration;
+    }
+
+    /**
+     * Save the specified configuration array to the given file in YAML format.
+     *
+     * @param File|string $fileToSave The file to write to.
+     * @param array $configuration The configuration to save
+     * @return void
+     * @internal
+     */
+    public function save($fileToSave, array $configuration)
+    {
+        $header = $this->getHeaderFromFile($fileToSave);
+        $yaml = Yaml::dump($configuration, 99, 2);
+        if ($fileToSave instanceof File) {
+            $fileToSave->setContents($header . LF . $yaml);
+        } else {
+            @file_put_contents($fileToSave, $header . LF . $yaml);
+        }
+    }
+
+    /**
+     * Read the header part from the given file. That means, every line
+     * until the first non comment line is found.
+     *
+     * @param File|string $file
+     * @return string The header of the given YAML file
+     */
+    protected function getHeaderFromFile($file): string
+    {
+        $header = '';
+        if ($file instanceof File) {
+            $fileLines = explode(LF, $file->getContents());
+        } else {
+            $fileLines = file($file);
+        }
+        foreach ($fileLines as $line) {
+            if (preg_match('/^#/', $line)) {
+                $header .= $line;
+            } else {
+                break;
+            }
+        }
+        return $header;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Controller/ControllerContext.php b/typo3/sysext/form/Classes/Mvc/Controller/ControllerContext.php
deleted file mode 100644
index bd002485e9df70fb046ac347e651a0a96b8230f3..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Mvc/Controller/ControllerContext.php
+++ /dev/null
@@ -1,85 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Mvc\Controller;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
-use TYPO3\CMS\Form\Domain\Model\Configuration;
-use TYPO3\CMS\Form\Domain\Model\ValidationElement;
-
-/**
- * Extension to the default Extbase Controller Context.
- */
-class ControllerContext extends \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext
-{
-    /**
-     * Extends a given default ControllerContext.
-     *
-     * @param \TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext
-     * @return ControllerContext
-     */
-    public static function extend(\TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext $source)
-    {
-        $controllerContext = \TYPO3\CMS\Form\Utility\FormUtility::getObjectManager()->get(self::class);
-        $propertyNames = ObjectAccess::getGettableProperties($source);
-        foreach ($propertyNames as $propertyName => $propertyValue) {
-            ObjectAccess::setProperty($controllerContext, $propertyName, $propertyValue);
-        }
-        return $controllerContext;
-    }
-
-    /**
-     * @var Configuration
-     */
-    protected $configuration;
-
-    /**
-     * @var ValidationElement
-     */
-    protected $validationElement;
-
-    /**
-     * @return Configuration
-     */
-    public function getConfiguration()
-    {
-        return $this->configuration;
-    }
-
-    /**
-     * @param Configuration $configuration
-     * @return ControllerContext
-     */
-    public function setConfiguration(Configuration $configuration)
-    {
-        $this->configuration = $configuration;
-        return $this;
-    }
-
-    /**
-     * @return ValidationElement
-     */
-    public function getValidationElement()
-    {
-        return $this->validationElement;
-    }
-
-    /**
-     * @param ValidationElement $validationElement
-     */
-    public function setValidationElement(ValidationElement $validationElement)
-    {
-        $this->validationElement = $validationElement;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Mvc/Persistence/Exception.php b/typo3/sysext/form/Classes/Mvc/Persistence/Exception.php
new file mode 100644
index 0000000000000000000000000000000000000000..2efc4a6d8c75f3c140d86ec0d128b4060d05132e
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Persistence/Exception.php
@@ -0,0 +1,27 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Persistence;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Exception as FormException;
+
+/**
+ * A generic Form persistence Exception
+ *
+ * @internal
+ */
+class Exception extends FormException
+{
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Persistence/Exception/NoUniqueIdentifierException.php b/typo3/sysext/form/Classes/Mvc/Persistence/Exception/NoUniqueIdentifierException.php
new file mode 100644
index 0000000000000000000000000000000000000000..fb267c3a0fef81607a170d1d3922d1b592efd9b8
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Persistence/Exception/NoUniqueIdentifierException.php
@@ -0,0 +1,25 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Persistence\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Mvc\Persistence\Exception;
+
+/**
+ * @internal
+ */
+class NoUniqueIdentifierException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Persistence/Exception/NoUniquePersistenceIdentifierException.php b/typo3/sysext/form/Classes/Mvc/Persistence/Exception/NoUniquePersistenceIdentifierException.php
new file mode 100644
index 0000000000000000000000000000000000000000..de1f7cd00beaf32eae6078c336f9b966a2ea6c17
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Persistence/Exception/NoUniquePersistenceIdentifierException.php
@@ -0,0 +1,25 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Persistence\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Mvc\Persistence\Exception;
+
+/**
+ * @internal
+ */
+class NoUniquePersistenceIdentifierException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Persistence/Exception/PersistenceManagerException.php b/typo3/sysext/form/Classes/Mvc/Persistence/Exception/PersistenceManagerException.php
new file mode 100644
index 0000000000000000000000000000000000000000..f8cf7baeae047a8d03a80bd01633264a710cf81b
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Persistence/Exception/PersistenceManagerException.php
@@ -0,0 +1,27 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Persistence\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Mvc\Persistence\Exception;
+
+/**
+ * Generic Persistence Manager Exception, to be thrown f.e. if a given form is not loadable
+ *
+ * @internal
+ */
+class PersistenceManagerException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Persistence/FormPersistenceManager.php b/typo3/sysext/form/Classes/Mvc/Persistence/FormPersistenceManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..fd19c9d33d84e6a51ce04a5a92a50be66a31f9fe
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Persistence/FormPersistenceManager.php
@@ -0,0 +1,493 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Persistence;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
+use TYPO3\CMS\Core\Resource\File;
+use TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter;
+use TYPO3\CMS\Core\Resource\Folder;
+use TYPO3\CMS\Core\Resource\ResourceStorage;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\PathUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Form\Mvc\Configuration\ConfigurationManagerInterface;
+use TYPO3\CMS\Form\Mvc\Configuration\YamlSource;
+use TYPO3\CMS\Form\Mvc\Persistence\Exception\NoUniqueIdentifierException;
+use TYPO3\CMS\Form\Mvc\Persistence\Exception\NoUniquePersistenceIdentifierException;
+use TYPO3\CMS\Form\Mvc\Persistence\Exception\PersistenceManagerException;
+
+/**
+ * Concrete implementation of the FormPersistenceManagerInterface
+ *
+ * Scope: frontend / backend
+ */
+class FormPersistenceManager implements FormPersistenceManagerInterface
+{
+
+    /**
+     * @var \TYPO3\CMS\Form\Mvc\Configuration\YamlSource
+     */
+    protected $yamlSource;
+
+    /**
+     * @var \TYPO3\CMS\Core\Resource\StorageRepository
+     */
+    protected $storageRepository;
+
+    /**
+     * @var array
+     */
+    protected $formSettings;
+
+    /**
+     * @param \TYPO3\CMS\Form\Mvc\Configuration\YamlSource $yamlSource
+     * @internal
+     */
+    public function injectYamlSource(\TYPO3\CMS\Form\Mvc\Configuration\YamlSource $yamlSource)
+    {
+        $this->yamlSource = $yamlSource;
+    }
+
+    /**
+     * @param \TYPO3\CMS\Core\Resource\StorageRepository $storageRepository
+     * @internal
+     */
+    public function injectStorageRepository(\TYPO3\CMS\Core\Resource\StorageRepository $storageRepository)
+    {
+        $this->storageRepository = $storageRepository;
+    }
+
+    /**
+     * @internal
+     */
+    public function initializeObject()
+    {
+        $this->formSettings = GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(ConfigurationManagerInterface::class)
+            ->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_YAML_SETTINGS, 'form');
+    }
+
+    /**
+     * Load the array formDefinition identified by $persistenceIdentifier, and return it.
+     * Only files with the extension .yaml are loaded.
+     * At this place there is no check if the file location is allowed.
+     *
+     * @param string $persistenceIdentifier
+     * @return array
+     * @throws PersistenceManagerException
+     * @internal
+     */
+    public function load(string $persistenceIdentifier): array
+    {
+        if (pathinfo($persistenceIdentifier, PATHINFO_EXTENSION) !== 'yaml') {
+            throw new PersistenceManagerException(sprintf('The file "%s" could not be loaded.', $persistenceIdentifier), 1477679819);
+        }
+
+        if (strpos($persistenceIdentifier, 'EXT:') === 0) {
+            $file = $persistenceIdentifier;
+        } else {
+            $file = $this->getFileByIdentifier($persistenceIdentifier);
+        }
+        return $this->yamlSource->load([$file]);
+    }
+
+    /**
+     * Save the array form representation identified by $persistenceIdentifier.
+     * Only files with the extension .yaml are saved.
+     * If the formDefinition is located within a EXT: resource, save is only
+     * allowed if the configuration path
+     * TYPO3.CMS.Form.persistenceManager.allowSaveToExtensionPaths
+     * is set to true.
+     *
+     * @param string $persistenceIdentifier
+     * @param array $formDefinition
+     * @return void
+     * @throws PersistenceManagerException
+     * @internal
+     */
+    public function save(string $persistenceIdentifier, array $formDefinition)
+    {
+        if (pathinfo($persistenceIdentifier, PATHINFO_EXTENSION) !== 'yaml') {
+            throw new PersistenceManagerException(sprintf('The file "%s" could not be saved.', $persistenceIdentifier), 1477679820);
+        }
+
+        if (strpos($persistenceIdentifier, 'EXT:') === 0) {
+            if (!$this->formSettings['persistenceManager']['allowSaveToExtensionPaths']) {
+                throw new PersistenceManagerException('Save to extension paths is not allowed.', 1477680881);
+            }
+            $fileToSave = GeneralUtility::getFileAbsFileName($persistenceIdentifier);
+        } else {
+            $fileToSave = $this->getOrCreateFile($persistenceIdentifier);
+        }
+
+        $this->yamlSource->save($fileToSave, $formDefinition);
+    }
+
+    /**
+     * Delete the form representation identified by $persistenceIdentifier.
+     * Only files with the extension .yaml are removed.
+     * formDefinitions within an EXT: resource are not removable.
+     *
+     * @param string $persistenceIdentifier
+     * @return void
+     * @throws PersistenceManagerException
+     * @internal
+     */
+    public function delete(string $persistenceIdentifier)
+    {
+        if (pathinfo($persistenceIdentifier, PATHINFO_EXTENSION) !== 'yaml') {
+            throw new PersistenceManagerException(sprintf('The file "%s" could not be removed.', $persistenceIdentifier), 1472239534);
+        }
+        if (!$this->exists($persistenceIdentifier)) {
+            throw new PersistenceManagerException(sprintf('The file "%s" could not be removed.', $persistenceIdentifier), 1472239535);
+        }
+        if (strpos($persistenceIdentifier, 'EXT:') === 0) {
+            throw new PersistenceManagerException(sprintf('The file "%s" could not be removed.', $persistenceIdentifier), 1472239536);
+        }
+
+        list($storageUid, $fileIdentifier) = explode(':', $persistenceIdentifier, 2);
+        $storage = $this->getStorageByUid((int)$storageUid);
+        $file = $storage->getFile($fileIdentifier);
+        if (!$storage->checkFileActionPermission('delete', $file)) {
+            throw new PersistenceManagerException(sprintf('No delete access to file "%s".', $persistenceIdentifier), 1472239516);
+        }
+        $storage->deleteFile($file);
+    }
+
+    /**
+     * Check whether a form with the specified $persistenceIdentifier exists
+     *
+     * @param string $persistenceIdentifier
+     * @return bool TRUE if a form with the given $persistenceIdentifier can be loaded, otherwise FALSE
+     * @internal
+     */
+    public function exists(string $persistenceIdentifier): bool
+    {
+        $exists = false;
+        if (pathinfo($persistenceIdentifier, PATHINFO_EXTENSION) === 'yaml') {
+            if (strpos($persistenceIdentifier, 'EXT:') === 0) {
+                $exists = file_exists(GeneralUtility::getFileAbsFileName($persistenceIdentifier));
+            } else {
+                list($storageUid, $fileIdentifier) = explode(':', $persistenceIdentifier, 2);
+                $storage = $this->getStorageByUid((int)$storageUid);
+                $exists = $storage->hasFile($fileIdentifier);
+            }
+        }
+        return $exists;
+    }
+
+    /**
+     * List all form definitions which can be loaded through this form persistence
+     * manager.
+     *
+     * Returns an associative array with each item containing the keys 'name' (the human-readable name of the form)
+     * and 'persistenceIdentifier' (the unique identifier for the Form Persistence Manager e.g. the path to the saved form definition).
+     *
+     * @return array in the format [['name' => 'Form 01', 'persistenceIdentifier' => 'path1'], [ .... ]]
+     * @internal
+     */
+    public function listForms(): array
+    {
+        $fileExtensionFilter = GeneralUtility::makeInstance(FileExtensionFilter::class);
+        $fileExtensionFilter->setAllowedFileExtensions(['yaml']);
+
+        $identifiers = [];
+        $forms = [];
+        /** @var \TYPO3\CMS\Core\Resource\Folder $folder */
+        foreach ($this->getAccessibleFormStorageFolders() as $folder) {
+            $storage = $folder->getStorage();
+            $storage->addFileAndFolderNameFilter([$fileExtensionFilter, 'filterFileList']);
+
+            $files = $folder->getFiles(0, 0, Folder::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS, true);
+            foreach ($files as $file) {
+                $persistenceIdentifier = $storage->getUid() . ':' . $file->getIdentifier();
+
+                $form = $this->load($persistenceIdentifier);
+                $forms[] = [
+                    'identifier' => $form['identifier'],
+                    'name' => isset($form['label']) ? $form['label'] : $form['identifier'],
+                    'persistenceIdentifier' => $persistenceIdentifier,
+                    'readOnly' => false,
+                    'location' => 'storage',
+                    'duplicateIdentifier' => false,
+                ];
+                $identifiers[$form['identifier']]++;
+            }
+            $storage->resetFileAndFolderNameFiltersToDefault();
+        }
+
+        foreach ($this->getAccessibleExtensionFolders() as $relativePath => $fullPath) {
+            $relativePath = rtrim($relativePath, '/') . '/';
+            foreach (new \DirectoryIterator($fullPath) as $fileInfo) {
+                if ($fileInfo->getExtension() !== 'yaml') {
+                    continue;
+                }
+                $form = $this->load($relativePath . $fileInfo->getFilename());
+                $forms[] = [
+                    'identifier' => $form['identifier'],
+                    'name' => isset($form['label']) ? $form['label'] : $form['identifier'],
+                    'persistenceIdentifier' => $relativePath . $fileInfo->getFilename(),
+                    'readOnly' => $this->formSettings['persistenceManager']['allowSaveToExtensionPaths'] ? false: true,
+                    'location' => 'extension',
+                    'duplicateIdentifier' => false,
+                ];
+                $identifiers[$form['identifier']]++;
+            }
+        }
+
+        foreach ($identifiers as $identifier => $count) {
+            if ($count > 1) {
+                foreach ($forms as &$formDefinition) {
+                    if ($formDefinition['identifier'] === $identifier) {
+                        $formDefinition['duplicateIdentifier'] = true;
+                    }
+                }
+            }
+        }
+
+        return $forms;
+    }
+
+    /**
+     * Return a list of all accessible file mountpoints for the
+     * current backend user.
+     *
+     * Only registered mountpoints from
+     * TYPO3.CMS.Form.persistenceManager.allowedFileMounts
+     * are listet.
+     *
+     * @return Folder[]
+     * @internal
+     */
+    public function getAccessibleFormStorageFolders(): array
+    {
+        $storageFolders = [];
+        if (
+            !isset($this->formSettings['persistenceManager']['allowedFileMounts'])
+            || !is_array($this->formSettings['persistenceManager']['allowedFileMounts'])
+            || empty($this->formSettings['persistenceManager']['allowedFileMounts'])
+        ) {
+            return $storageFolders;
+        }
+
+        foreach ($this->formSettings['persistenceManager']['allowedFileMounts'] as $allowedFileMount) {
+            list($storageUid, $fileMountIdentifier) = explode(':', $allowedFileMount, 2);
+            $fileMountIdentifier = rtrim($fileMountIdentifier, '/') . '/';
+
+            try {
+                $storage = $this->getStorageByUid((int)$storageUid);
+            } catch (PersistenceManagerException $e) {
+                continue;
+            }
+
+            try {
+                $folder = $storage->getFolder($fileMountIdentifier);
+            } catch (InsufficientFolderAccessPermissionsException $e) {
+                continue;
+            }
+            $storageFolders[$allowedFileMount] = $folder;
+        }
+        return $storageFolders;
+    }
+
+    /**
+     * Return a list of all accessible extension folders
+     *
+     * Only registered mountpoints from
+     * TYPO3.CMS.Form.persistenceManager.allowedExtensionPaths
+     * are listet.
+     *
+     * @return array
+     * @internal
+     */
+    public function getAccessibleExtensionFolders(): array
+    {
+        $extensionFolders = [];
+        if (
+            !isset($this->formSettings['persistenceManager']['allowedExtensionPaths'])
+            || !is_array($this->formSettings['persistenceManager']['allowedExtensionPaths'])
+            || empty($this->formSettings['persistenceManager']['allowedExtensionPaths'])
+        ) {
+            return $extensionFolders;
+        }
+
+        foreach ($this->formSettings['persistenceManager']['allowedExtensionPaths'] as $allowedExtensionPath) {
+            if (strpos($allowedExtensionPath, 'EXT:') !== 0) {
+                continue;
+            }
+
+            $allowedExtensionFullPath = GeneralUtility::getFileAbsFileName($allowedExtensionPath);
+            if (!file_exists($allowedExtensionFullPath)) {
+                continue;
+            }
+            $extensionFolders[$allowedExtensionPath] = $allowedExtensionFullPath;
+        }
+        return $extensionFolders;
+    }
+
+    /**
+     * This takes a form identifier and returns a unique persistence identifier for it.
+     * By default this is just similar to the identifier. But if a form with the same persistence identifier already
+     * exists a suffix is appended until the persistence identifier is unique.
+     *
+     * @param string $formIdentifier lowerCamelCased form identifier
+     * @param string $savePath
+     * @return string unique form persistence identifier
+     * @throws NoUniquePersistenceIdentifierException
+     * @internal
+     */
+    public function getUniquePersistenceIdentifier(string $formIdentifier, string $savePath): string
+    {
+        $savePath = rtrim($savePath, '/') . '/';
+        $formPersistenceIdentifier = $savePath . $formIdentifier . '.yaml';
+        if (!$this->exists($formPersistenceIdentifier)) {
+            return $formPersistenceIdentifier;
+        }
+        for ($attempts = 1; $attempts < 100; $attempts++) {
+            $formPersistenceIdentifier = $savePath . sprintf('%s_%d', $formIdentifier, $attempts) . '.yaml';
+            if (!$this->exists($formPersistenceIdentifier)) {
+                return $formPersistenceIdentifier;
+            }
+        }
+        $formPersistenceIdentifier = $savePath . sprintf('%s_%d', $formIdentifier, time()) . '.yaml';
+        if (!$this->exists($formPersistenceIdentifier)) {
+            return $formPersistenceIdentifier;
+        }
+
+        throw new NoUniquePersistenceIdentifierException(
+            sprintf('Could not find a unique persistence identifier for form identifier "%s" after %d attempts', $formIdentifier, $attempts),
+            1476010403
+        );
+    }
+
+    /**
+     * This takes a form identifier and returns a unique identifier for it.
+     * If a formDefinition with the same identifier already exists a suffix is
+     * appended until the identifier is unique.
+     *
+     * @param string $identifier
+     * @return string unique form identifier
+     * @throws NoUniqueIdentifierException
+     * @internal
+     */
+    public function getUniqueIdentifier(string $identifier): string
+    {
+        $originalIdentifier = $identifier;
+        if ($this->checkForDuplicateIdentifier($identifier)) {
+            for ($attempts = 1; $attempts < 100; $attempts++) {
+                $identifier = sprintf('%s_%d', $originalIdentifier, $attempts);
+                if (!$this->checkForDuplicateIdentifier($identifier)) {
+                    return $identifier;
+                }
+            }
+            $identifier = $originalIdentifier . '_' . time();
+            if ($this->checkForDuplicateIdentifier($identifier)) {
+                throw new NoUniqueIdentifierException(
+                    sprintf('Could not find a unique identifier for form identifier "%s" after %d attempts', $identifier, $attempts),
+                    1477688567
+                );
+            }
+        }
+        return  $identifier;
+    }
+
+    /**
+     * Check if a identifier is already used by a formDefintion.
+     *
+     * @param string $identifier
+     * @return bool
+     * @internal
+     */
+    public function checkForDuplicateIdentifier(string $identifier): bool
+    {
+        $identifierUsed = false;
+        foreach ($this->listForms() as $formDefinition) {
+            if ($formDefinition['identifier'] === $identifier) {
+                $identifierUsed = true;
+                break;
+            }
+        }
+        return $identifierUsed;
+    }
+
+    /**
+     * Returns a File object for a given $persistenceIdentifier
+     *
+     * @param string $persistenceIdentifier
+     * @return File
+     * @throws PersistenceManagerException
+     */
+    protected function getFileByIdentifier(string $persistenceIdentifier): File
+    {
+        list($storageUid, $fileIdentifier) = explode(':', $persistenceIdentifier, 2);
+        $storage = $this->getStorageByUid((int)$storageUid);
+        $file = $storage->getFile($fileIdentifier);
+        if (!$storage->checkFileActionPermission('read', $file)) {
+            throw new PersistenceManagerException(sprintf('No read access to file "%s".', $persistenceIdentifier), 1471630578);
+        }
+        return $file;
+    }
+
+    /**
+     * Returns a File object for a given $persistenceIdentifier.
+     * If no file for this identifier exists a new object will be
+     * created.
+     *
+     * @param string $persistenceIdentifier
+     * @return File
+     * @throws PersistenceManagerException
+     */
+    protected function getOrCreateFile(string $persistenceIdentifier): File
+    {
+        list($storageUid, $fileIdentifier) = explode(':', $persistenceIdentifier, 2);
+        $storage = $this->getStorageByUid((int)$storageUid);
+        $pathinfo = PathUtility::pathinfo($fileIdentifier);
+
+        if (!$storage->hasFolder($pathinfo['dirname'])) {
+            throw new PersistenceManagerException(sprintf('Could not create folder "%s".', $pathinfo['dirname']), 1471630579);
+        }
+        $folder = $storage->getFolder($pathinfo['dirname']);
+        if (!$storage->checkFolderActionPermission('write', $folder)) {
+            throw new PersistenceManagerException(sprintf('No write access to folder "%s".', $pathinfo['dirname']), 1471630580);
+        }
+
+        if (!$storage->hasFile($fileIdentifier)) {
+            $file = $folder->createFile($pathinfo['basename']);
+        } else {
+            $file = $storage->getFile($fileIdentifier);
+        }
+        return $file;
+    }
+
+    /**
+     * Returns a ResourceStorage for a given uid
+     *
+     * @param int $storageUid
+     * @return ResourceStorage
+     * @throws PersistenceManagerException
+     */
+    protected function getStorageByUid(int $storageUid): ResourceStorage
+    {
+        $storage = $this->storageRepository->findByUid($storageUid);
+        if (
+            !$storage instanceof ResourceStorage
+            || !$storage->isBrowsable()
+        ) {
+            throw new PersistenceManagerException(sprintf('Could not access storage with uid "%d".', $storageUid), 1471630581);
+        }
+        return $storage;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Persistence/FormPersistenceManagerInterface.php b/typo3/sysext/form/Classes/Mvc/Persistence/FormPersistenceManagerInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..f1cd660ddb62fb7e5172ba07315cc955a7c0f2a7
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Persistence/FormPersistenceManagerInterface.php
@@ -0,0 +1,110 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Persistence;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Resource\Folder;
+
+/**
+ * The form persistence manager interface
+ *
+ * Scope: frontend / backend
+ */
+interface FormPersistenceManagerInterface
+{
+
+    /**
+     * Load the array form representation identified by $persistenceIdentifier, and return it
+     *
+     * @param string $persistenceIdentifier
+     * @return array
+     * @api
+     */
+    public function load(string $persistenceIdentifier): array;
+
+    /**
+     * Save the array form representation identified by $persistenceIdentifier
+     *
+     * @param string $persistenceIdentifier
+     * @param array $formDefinition
+     * @api
+     */
+    public function save(string $persistenceIdentifier, array $formDefinition);
+
+    /**
+     * Check whether a form with the specified $persistenceIdentifier exists
+     *
+     * @param string $persistenceIdentifier
+     * @return bool TRUE if a form with the given $persistenceIdentifier can be loaded, otherwise FALSE
+     * @api
+     */
+    public function exists(string $persistenceIdentifier): bool;
+
+    /**
+     * Delete the form representation identified by $persistenceIdentifier
+     *
+     * @param string $persistenceIdentifier
+     * @return void
+     * @api
+     */
+    public function delete(string $persistenceIdentifier);
+
+    /**
+     * List all form definitions which can be loaded through this form persistence
+     * manager.
+     *
+     * Returns an associative array with each item containing the keys 'name' (the human-readable name of the form)
+     * and 'persistenceIdentifier' (the unique identifier for the Form Persistence Manager e.g. the path to the saved form definition).
+     *
+     * @return array in the format [['name' => 'Form 01', 'persistenceIdentifier' => 'path1'], [ .... ]]
+     * @api
+     */
+    public function listForms(): array;
+
+    /**
+     * Return a list of all accessible file mount points
+     *
+     * @return Folder[]
+     * @api
+     */
+    public function getAccessibleFormStorageFolders(): array;
+
+    /**
+     * Return a list of all accessible extension folders
+     *
+     * @return array
+     * @api
+     */
+    public function getAccessibleExtensionFolders(): array;
+
+    /**
+     * This takes a form identifier and returns a unique persistence identifier for it.
+     *
+     * @param string $formIdentifier
+     * @param string $savePath
+     * @return string
+     * @api
+     */
+    public function getUniquePersistenceIdentifier(string $formIdentifier, string $savePath): string;
+
+    /**
+     * Check if a identifier is already used by a formDefintion.
+     *
+     * @param string $identifier
+     * @return bool
+     * @api
+     */
+    public function checkForDuplicateIdentifier(string $identifier): bool;
+}
diff --git a/typo3/sysext/form/Classes/Mvc/ProcessingRule.php b/typo3/sysext/form/Classes/Mvc/ProcessingRule.php
new file mode 100644
index 0000000000000000000000000000000000000000..6b8949a420b5bd2e65122cd354171616987181dc
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/ProcessingRule.php
@@ -0,0 +1,181 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Error\Result;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\Property\PropertyMapper;
+use TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration;
+use TYPO3\CMS\Extbase\Validation\Validator\ConjunctionValidator;
+use TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface;
+
+/**
+ * A processing Rule contains information for property mapping and validation.
+ *
+ * Scope: frontend
+ * **This class is NOT meant to be sub classed by developers.**
+ * @internal
+ */
+class ProcessingRule
+{
+
+    /**
+     * The target data type the data should be converted to
+     *
+     * @var string
+     */
+    protected $dataType;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration
+     */
+    protected $propertyMappingConfiguration;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Validation\Validator\ConjunctionValidator
+     */
+    protected $validator;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Error\Result
+     */
+    protected $processingMessages;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Property\PropertyMapper
+     */
+    protected $propertyMapper;
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration $propertyMappingConfiguration
+     * @return void
+     * @internal
+     */
+    public function injectPropertyMappingConfiguration(\TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration $propertyMappingConfiguration)
+    {
+        $this->propertyMappingConfiguration = $propertyMappingConfiguration;
+    }
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Validation\Validator\ConjunctionValidator $validator
+     * @return void
+     * @internal
+     */
+    public function injectConjunctionValidator(\TYPO3\CMS\Extbase\Validation\Validator\ConjunctionValidator $validator)
+    {
+        $this->validator = $validator;
+    }
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Property\PropertyMapper $propertyMapper
+     * @return void
+     * @internal
+     */
+    public function injectPropertyMapper(\TYPO3\CMS\Extbase\Property\PropertyMapper $propertyMapper)
+    {
+        $this->propertyMapper = $propertyMapper;
+    }
+
+    /**
+     * Constructs this processing rule
+     * @internal
+     */
+    public function __construct()
+    {
+        $this->processingMessages = GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(Result::class);
+    }
+
+    /**
+     * @return PropertyMappingConfiguration
+     * @internal
+     */
+    public function getPropertyMappingConfiguration(): PropertyMappingConfiguration
+    {
+        return $this->propertyMappingConfiguration;
+    }
+
+    /**
+     * @return string
+     * @internal
+     */
+    public function getDataType(): string
+    {
+        return $this->dataType;
+    }
+
+    /**
+     * @param string $dataType
+     * @internal
+     */
+    public function setDataType(string $dataType)
+    {
+        $this->dataType = $dataType;
+    }
+
+    /**
+     * Returns the child validators of the ConjunctionValidator that is bound to this processing rule
+     *
+     * @return \SplObjectStorage<ValidatorInterface>
+     * @internal
+     */
+    public function getValidators(): \SplObjectStorage
+    {
+        return $this->validator->getValidators();
+    }
+
+    /**
+     * @param ValidatorInterface $validator
+     * @return void
+     * @internal
+     */
+    public function addValidator(ValidatorInterface $validator)
+    {
+        $this->validator->addValidator($validator);
+    }
+
+    /**
+     * @param mixed $value
+     * @return mixed
+     * @internal
+     */
+    public function process($value)
+    {
+        if ($this->dataType !== null) {
+            $value = $this->propertyMapper->convert($value, $this->dataType, $this->propertyMappingConfiguration);
+            $messages = $this->propertyMapper->getMessages();
+        } else {
+            $messages = GeneralUtility::makeInstance(ObjectManager::class)
+                ->get(Result::class);
+        }
+
+        $validationResult = $this->validator->validate($value);
+        $messages->merge($validationResult);
+
+        $this->processingMessages->merge($messages);
+        return $value;
+    }
+
+    /**
+     * @return Result
+     * @internal
+     */
+    public function getProcessingMessages(): Result
+    {
+        return $this->processingMessages;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Property/TypeConverter/UploadedFileReferenceConverter.php b/typo3/sysext/form/Classes/Mvc/Property/TypeConverter/UploadedFileReferenceConverter.php
new file mode 100644
index 0000000000000000000000000000000000000000..7ced599d51037afd1d69cf024a69aabf48d7e42e
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Property/TypeConverter/UploadedFileReferenceConverter.php
@@ -0,0 +1,291 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Property\TypeConverter;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Resource\File as File;
+use TYPO3\CMS\Core\Resource\FileReference as CoreFileReference;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Domain\Model\AbstractFileFolder;
+use TYPO3\CMS\Extbase\Domain\Model\FileReference as ExtbaseFileReference;
+use TYPO3\CMS\Extbase\Error\Error;
+use TYPO3\CMS\Extbase\Property\Exception\TypeConverterException;
+use TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface;
+use TYPO3\CMS\Extbase\Property\TypeConverter\AbstractTypeConverter;
+use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
+
+/**
+ * Class UploadedFileReferenceConverter
+ *
+ * Scope: frontend
+ * @internal
+ */
+class UploadedFileReferenceConverter extends AbstractTypeConverter
+{
+
+    /**
+     * Folder where the file upload should go to (including storage).
+     */
+    const CONFIGURATION_UPLOAD_FOLDER = 1;
+
+    /**
+     * How to handle a upload when the name of the uploaded file conflicts.
+     */
+    const CONFIGURATION_UPLOAD_CONFLICT_MODE = 2;
+
+    /**
+     * Validator for file types
+     */
+    const CONFIGURATION_FILE_VALIDATORS = 4;
+
+    /**
+     * @var string
+     */
+    protected $defaultUploadFolder = '1:/user_upload/';
+
+    /**
+     * One of 'cancel', 'replace', 'rename'
+     *
+     * @var string
+     */
+    protected $defaultConflictMode = 'rename';
+
+    /**
+     * @var array
+     */
+    protected $sourceTypes = ['array'];
+
+    /**
+     * @var string
+     */
+    protected $targetType = ExtbaseFileReference::class;
+
+    /**
+     * Take precedence over the available FileReferenceConverter
+     *
+     * @var int
+     */
+    protected $priority = 2;
+
+    /**
+     * @var \TYPO3\CMS\Core\Resource\FileInterface[]
+     */
+    protected $convertedResources = [];
+
+    /**
+     * @var \TYPO3\CMS\Core\Resource\ResourceFactory
+     */
+    protected $resourceFactory;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Security\Cryptography\HashService
+     */
+    protected $hashService;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
+     */
+    protected $persistenceManager;
+
+    /**
+     * @param \TYPO3\CMS\Core\Resource\ResourceFactory $resourceFactory
+     * @return void
+     * @internal
+     */
+    public function injectResourceFactory(\TYPO3\CMS\Core\Resource\ResourceFactory $resourceFactory)
+    {
+        $this->resourceFactory = $resourceFactory;
+    }
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Security\Cryptography\HashService $hashService
+     * @return void
+     * @internal
+     */
+    public function injectHashService(\TYPO3\CMS\Extbase\Security\Cryptography\HashService $hashService)
+    {
+        $this->hashService = $hashService;
+    }
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager
+     * @return void
+     * @internal
+     */
+    public function injectPersistenceManager(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager)
+    {
+        $this->persistenceManager = $persistenceManager;
+    }
+
+    /**
+     * Actually convert from $source to $targetType, taking into account the fully
+     * built $convertedChildProperties and $configuration.
+     *
+     * @param string|int $source
+     * @param string $targetType
+     * @param array $convertedChildProperties
+     * @param PropertyMappingConfigurationInterface $configuration
+     * @return AbstractFileFolder
+     * @internal
+     */
+    public function convertFrom($source, $targetType, array $convertedChildProperties = [], PropertyMappingConfigurationInterface $configuration = null)
+    {
+        if (!isset($source['error']) || $source['error'] === \UPLOAD_ERR_NO_FILE) {
+            if (isset($source['submittedFile']['resourcePointer'])) {
+                try {
+                    $resourcePointer = $this->hashService->validateAndStripHmac($source['submittedFile']['resourcePointer']);
+                    if (strpos($resourcePointer, 'file:') === 0) {
+                        $fileUid = substr($resourcePointer, 5);
+                        return $this->createFileReferenceFromFalFileObject($this->resourceFactory->getFileObject($fileUid));
+                    } else {
+                        return $this->createFileReferenceFromFalFileReferenceObject($this->resourceFactory->getFileReferenceObject($resourcePointer), $resourcePointer);
+                    }
+                } catch (\InvalidArgumentException $e) {
+                    // Nothing to do. No file is uploaded and resource pointer is invalid. Discard!
+                }
+            }
+            return null;
+        }
+
+        if ($source['error'] !== \UPLOAD_ERR_OK) {
+            return $this->objectManager->get(Error::class, $this->getUploadErrorMessage($source['error']), 1471715915);
+        }
+
+        if (isset($this->convertedResources[$source['tmp_name']])) {
+            return $this->convertedResources[$source['tmp_name']];
+        }
+
+        try {
+            $resource = $this->importUploadedResource($source, $configuration);
+        } catch (\Exception $e) {
+            return $this->objectManager->get(Error::class, $e->getMessage(), $e->getCode());
+        }
+
+        $this->convertedResources[$source['tmp_name']] = $resource;
+        return $resource;
+    }
+
+    /**
+     * Import a resource and respect configuration given for properties
+     *
+     * @param array $uploadInfo
+     * @param PropertyMappingConfigurationInterface $configuration
+     * @return ExtbaseFileReference
+     * @throws TypeConverterException
+     */
+    protected function importUploadedResource(
+        array $uploadInfo,
+        PropertyMappingConfigurationInterface $configuration
+    ): ExtbaseFileReference {
+        if (!GeneralUtility::verifyFilenameAgainstDenyPattern($uploadInfo['name'])) {
+            throw new TypeConverterException('Uploading files with PHP file extensions is not allowed!', 1471710357);
+        }
+
+        $uploadFolderId = $configuration->getConfigurationValue(self::class, self::CONFIGURATION_UPLOAD_FOLDER) ?: $this->defaultUploadFolder;
+        $conflictMode = $configuration->getConfigurationValue(self::class, self::CONFIGURATION_UPLOAD_CONFLICT_MODE) ?: $this->defaultConflictMode;
+
+        $uploadFolder = $this->resourceFactory->retrieveFileOrFolderObject($uploadFolderId);
+        $uploadedFile =  $uploadFolder->addUploadedFile($uploadInfo, $conflictMode);
+
+        $validators = $configuration->getConfigurationValue(self::class, self::CONFIGURATION_FILE_VALIDATORS);
+        if (is_array($validators)) {
+            foreach ($validators as $validator) {
+                if ($validator instanceof AbstractValidator) {
+                    $validationResult = $validator->validate($uploadedFile);
+                    if ($validationResult->hasErrors()) {
+                        $uploadedFile->getStorage()->deleteFile($uploadedFile);
+                        throw new TypeConverterException($validationResult->getErrors()[0]->getMessage(), 1471708999);
+                    }
+                }
+            }
+        }
+
+        $resourcePointer = isset($uploadInfo['submittedFile']['resourcePointer']) && strpos($uploadInfo['submittedFile']['resourcePointer'], 'file:') === false
+            ? $this->hashService->validateAndStripHmac($uploadInfo['submittedFile']['resourcePointer'])
+            : null;
+
+        $fileReferenceModel = $this->createFileReferenceFromFalFileObject($uploadedFile, $resourcePointer);
+
+        return $fileReferenceModel;
+    }
+
+    /**
+     * @param File $file
+     * @param int $resourcePointer
+     * @return ExtbaseFileReference
+     */
+    protected function createFileReferenceFromFalFileObject(
+        File $file,
+        int $resourcePointer = null
+    ): ExtbaseFileReference {
+        $fileReference = $this->resourceFactory->createFileReferenceObject(
+            [
+                'uid_local' => $file->getUid(),
+                'uid_foreign' => uniqid('NEW_'),
+                'uid' => uniqid('NEW_'),
+                'crop' => null,
+            ]
+        );
+        return $this->createFileReferenceFromFalFileReferenceObject($fileReference, $resourcePointer);
+    }
+
+    /**
+     * @param CoreFileReference $falFileReference
+     * @param int $resourcePointer
+     * @return ExtbaseFileReference
+     */
+    protected function createFileReferenceFromFalFileReferenceObject(
+        CoreFileReference $falFileReference,
+        int $resourcePointer = null
+    ): ExtbaseFileReference {
+        if ($resourcePointer === null) {
+            $fileReference = $this->objectManager->get(ExtbaseFileReference::class);
+        } else {
+            $fileReference = $this->persistenceManager->getObjectByIdentifier($resourcePointer, ExtbaseFileReference::class, false);
+        }
+
+        $fileReference->setOriginalResource($falFileReference);
+        return $fileReference;
+    }
+
+    /**
+     * Returns a human-readable message for the given PHP file upload error
+     * constant.
+     *
+     * @param int $errorCode
+     * @return string
+     */
+    protected function getUploadErrorMessage(int $errorCode): string
+    {
+        switch ($errorCode) {
+            case \UPLOAD_ERR_INI_SIZE:
+                return 'The uploaded file exceeds the upload_max_filesize directive in php.ini';
+            case \UPLOAD_ERR_FORM_SIZE:
+                return 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form';
+            case \UPLOAD_ERR_PARTIAL:
+                return 'The uploaded file was only partially uploaded';
+            case \UPLOAD_ERR_NO_FILE:
+                return 'No file was uploaded';
+            case \UPLOAD_ERR_NO_TMP_DIR:
+                return 'Missing a temporary folder';
+            case \UPLOAD_ERR_CANT_WRITE:
+                return 'Failed to write file to disk';
+            case \UPLOAD_ERR_EXTENSION:
+                return 'File upload stopped by extension';
+            default:
+                return 'Unknown upload error';
+        }
+    }
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Validation/CountValidator.php b/typo3/sysext/form/Classes/Mvc/Validation/CountValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..1d21963e671a30169d59d831ba28831c6b630ddf
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Validation/CountValidator.php
@@ -0,0 +1,69 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Validation;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
+
+/**
+ * Validator for countable types
+ *
+ * Scope: frontend
+ * @internal
+ */
+class CountValidator extends AbstractValidator
+{
+    /**
+     * @var array
+     */
+    protected $supportedOptions = [
+        'minimum' => [0, 'The minimum count to accept', 'integer'],
+        'maximum' => [PHP_INT_MAX, 'The maximum count to accept', 'integer']
+    ];
+
+    /**
+     * The given value is valid if it is an array or \Countable that contains the specified amount of elements.
+     *
+     * @param mixed $value
+     * @return void
+     * @api
+     */
+    public function isValid($value)
+    {
+        if (!is_array($value) && !($value instanceof \Countable)) {
+            $this->addError(
+                $this->translateErrorMessage(
+                    'validation.error.1475002976',
+                    'form'
+                ),
+                1475002976
+            );
+            return;
+        }
+
+        $minimum = (int)$this->options['minimum'];
+        $maximum = (int)$this->options['maximum'];
+        if (count($value) < $minimum || count($value) > $maximum) {
+            $this->addError(
+                $this->translateErrorMessage(
+                    'validation.error.1475002994',
+                    'form',
+                    [$minimum, $maximum]
+                ),
+                1475002994
+            );
+        }
+    }
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Validation/EmptyValidator.php b/typo3/sysext/form/Classes/Mvc/Validation/EmptyValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..5e1204a5520e2b9c3c2c9bbb29dcfdd0ec16460d
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Validation/EmptyValidator.php
@@ -0,0 +1,55 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Validation;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
+
+/**
+ * Validator for empty values.
+ *
+ * Scope: frontend
+ * @api
+ */
+class EmptyValidator extends AbstractValidator
+{
+    /**
+     * This validator always needs to be executed even if the given value is empty.
+     * See AbstractValidator::validate()
+     *
+     * @var bool
+     */
+    protected $acceptsEmptyValues = true;
+
+    /**
+     * Checks if the given property ($propertyValue) is empty (NULL, empty string, empty array or empty object).
+     *
+     * @param mixed $value The value that should be validated
+     * @return void
+     * @api
+     */
+    public function isValid($value)
+    {
+        if (!empty($value)) {
+            $this->addError(
+                $this->translateErrorMessage(
+                    'validation.error.1476396435',
+                    'form'
+                ),
+                1476396435
+            );
+        }
+    }
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Validation/Exception/InvalidValidationOptionsException.php b/typo3/sysext/form/Classes/Mvc/Validation/Exception/InvalidValidationOptionsException.php
new file mode 100644
index 0000000000000000000000000000000000000000..5386627f7f801f1dc7408f1d03a0e39ba3ef5d53
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Validation/Exception/InvalidValidationOptionsException.php
@@ -0,0 +1,25 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Validation\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Exception;
+
+/**
+ * @api
+ */
+class InvalidValidationOptionsException extends Exception
+{
+}
diff --git a/typo3/sysext/form/Classes/Mvc/Validation/MimeTypeValidator.php b/typo3/sysext/form/Classes/Mvc/Validation/MimeTypeValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..4cf7b93a030e1eedc3bdcf6965c1b3b9f86f847c
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/Validation/MimeTypeValidator.php
@@ -0,0 +1,90 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\Validation;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Resource\File;
+use TYPO3\CMS\Extbase\Domain\Model\FileReference;
+use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
+use TYPO3\CMS\Form\Mvc\Validation\Exception\InvalidValidationOptionsException;
+
+/**
+ * Validator for mime types
+ *
+ * Scope: frontend
+ * @api
+ */
+class MimeTypeValidator extends AbstractValidator
+{
+    /**
+     * @var array
+     */
+    protected $supportedOptions = [
+        'allowedMimeTypes' => [null, 'Allowed mime types (using */* IANA media types)', 'array', true]
+    ];
+
+    /**
+     * The given $value is valid if it is an FileReference of the
+     * configured type (one of the image/* IANA media subtypes)
+     *
+     * Note: a value of NULL or empty string ('') is considered valid
+     *
+     * @param FileReference|File $resource The resource that should be validated
+     * @return void
+     * @api
+     */
+    public function isValid($resource)
+    {
+        $this->validateOptions();
+
+        if ($resource instanceof FileReference) {
+            $resource = $resource->getOriginalResource();
+        } elseif (!$resource instanceof File) {
+            $this->addError(
+                $this->translateErrorMessage(
+                    'validation.error.1471708997',
+                    'form'
+                ),
+                1471708997
+            );
+            return;
+        }
+
+        $allowedMimeTypes = $this->options['allowedMimeTypes'];
+        if (!in_array($resource->getMimeType(), $allowedMimeTypes, true)) {
+            $this->addError(
+                $this->translateErrorMessage(
+                    'validation.error.1471708998',
+                    'form',
+                    [$resource->getMimeType()]
+                ),
+                1471708998
+            );
+        }
+    }
+
+    /**
+     * Checks if this validator is correctly configured
+     *
+     * @return void
+     * @throws InvalidValidationOptionsException if the configured validation options are incorrect
+     */
+    protected function validateOptions()
+    {
+        if (!is_array($this->options['allowedMimeTypes']) || $this->options['allowedMimeTypes'] === []) {
+            throw new InvalidValidationOptionsException('The option "allowedMimeTypes" must be an array with at least one item.', 1471713296);
+        }
+    }
+}
diff --git a/typo3/sysext/form/Classes/Mvc/View/FormView.php b/typo3/sysext/form/Classes/Mvc/View/FormView.php
new file mode 100644
index 0000000000000000000000000000000000000000..8cac863e5763d51fa06a4e4f746b513bbb14df69
--- /dev/null
+++ b/typo3/sysext/form/Classes/Mvc/View/FormView.php
@@ -0,0 +1,233 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Mvc\View;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Fluid\View\AbstractTemplateView;
+use TYPO3\CMS\Form\Domain\Exception\RenderingException;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface;
+use TYPO3\CMS\Form\Domain\Renderer\RendererInterface;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+
+/**
+ * A fluid TemplateView implementation which used to render *Renderables*.
+ *
+ * The FormView is especially capable of rendering nested renderables
+ * as well, i.e a form with a page, with all FormElements.
+ *
+ * Options
+ * =======
+ *
+ * The FormView uses some rendering options which are of particular
+ * importance, as they determine how the form field is resolved to a path
+ * in the file system.
+ *
+ * All rendering options are retrieved from the renderable which shall be rendered,
+ * using the {@link \TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface::getRenderingOptions()}
+ * method.
+ *
+ * templateRootPaths
+ * -----------------
+ *
+ * Used to define several paths for templates, which will be tried in reversed
+ * order (the paths are searched from bottom to top). The first folder where
+ * the desired layout is found, is used. If the array keys are numeric,
+ * they are first sorted and then tried in reversed order.
+ *
+ * layoutRootPaths
+ * ---------------
+ *
+ * Used to define several paths for layouts, which will be tried in reversed
+ * order (the paths are searched from bottom to top). The first folder where
+ * the desired layout is found, is used. If the array keys are numeric,
+ * they are first sorted and then tried in reversed order.
+ *
+ * partialRootPaths
+ * ----------------
+ *
+ * Used to define several paths for partials, which will be tried in reversed
+ * order. The first folder where the desired partial is found, is used.
+ * The keys of the array define the order.
+ *
+ * renderableNameInTemplate
+ * ------------------------
+ *
+ * This is a mostly-internal setting which controls the name under which the current
+ * renderable is made available inside the template. For example, it controls that
+ * inside the template of a "Page", the Page object is available using the variable
+ * *page*.
+ *
+ * Rendering Child Renderables
+ * ===========================
+ *
+ * If a renderable wants to render child renderables, inside its template,
+ * it can do that using the <code><formvh:renderRenderable></code> ViewHelper.
+ *
+ * A template example from Page shall demonstrate this:
+ *
+ * <pre>
+ * {namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+ * <f:for each="{page.elements}" as="element">
+ *   <formvh:renderRenderable renderable="{element}" />
+ * </f:for>
+ * </pre>
+ *
+ * Rendering PHP Based Child Renderables
+ * =====================================
+ *
+ * If a child renderable has a *rendererClassName* set (i.e. {@link \TYPO3\CMS\Form\Domain\Model\FormElements\FormElementInterface::getRendererClassName()}
+ * returns a non-NULL string), this renderer is automatically instanciated
+ * and the rendering for this element is delegated to this Renderer.
+ *
+ * Scope: frontend
+ * **This class is NOT meant to be sub classed by developers.**
+ * @internal
+ */
+class FormView extends AbstractTemplateView
+{
+
+    /**
+     * @var \TYPO3\CMS\Form\Domain\Runtime\FormRuntime
+     */
+    protected $formRuntime;
+
+    /**
+     * @param FormRuntime $formRuntime
+     * @return void
+     * @internal
+     */
+    public function setFormRuntime(FormRuntime $formRuntime)
+    {
+        $this->formRuntime = $formRuntime;
+    }
+
+    /**
+     * @return FormRuntime
+     * @internal
+     */
+    public function getFormRuntime(): FormRuntime
+    {
+        return $this->formRuntime;
+    }
+
+    /**
+     * Render the $renderable and return the content.
+     *
+     * @param RootRenderable $renderable
+     * @return string
+     * @throws RenderingException
+     * @internal
+     */
+    public function renderRenderable(RootRenderableInterface $renderable): string
+    {
+        // Invoke the beforeRendering callback on the renderable
+        $renderable->beforeRendering($this->formRuntime);
+
+        if (
+            $renderable->getRendererClassName() !== null
+            && $renderable->getRendererClassName() !== $this->formRuntime->getRendererClassName()
+        ) {
+            // If a child renderable has a *rendererClassName* set
+            // then render it with this foreign renderer.
+            $rendererClassName = $renderable->getRendererClassName();
+            $renderer = GeneralUtility::makeInstance(ObjectManager::class)->get($rendererClassName);
+            if (!($renderer instanceof RendererInterface)) {
+                throw new RenderingException(
+                    sprintf('The renderer class "%s" for "%s" does not implement RendererInterface.', $rendererClassName, $renderable->getType()),
+                    1480286138
+                );
+            }
+            $renderer->setControllerContext($this->baseRenderingContext->getControllerContext());
+            $renderer->setFormRuntime($this->formRuntime);
+            return $renderer->render($renderable);
+        }
+
+        $renderingOptions = $renderable->getRenderingOptions();
+
+        if (!isset($renderingOptions['templateRootPaths'])) {
+            throw new RenderingException(
+                sprintf('The option templateRootPaths must be set for renderable "%s"', $renderable->getType()),
+                1480293084
+            );
+        }
+        if (!isset($renderingOptions['layoutRootPaths'])) {
+            throw new RenderingException(
+                sprintf('The option layoutRootPaths must be set for renderable "%s"', $renderable->getType()),
+                1480293085
+            );
+        }
+        if (!isset($renderingOptions['partialRootPaths'])) {
+            throw new RenderingException(
+                sprintf('The option partialRootPaths must be set for renderable "%s"', $renderable->getType()),
+                1480293086
+            );
+        }
+        if (!isset($renderingOptions['renderableNameInTemplate'])) {
+            throw new RenderingException(
+                sprintf('The option renderableNameInTemplate must be set for renderable "%s"', $renderable->getType()),
+                1480293087
+            );
+        }
+
+        $renderingContext = $this->getCurrentRenderingContext();
+        // Configure the fluid TemplateView with the rendering options
+        // from the renderable
+        $renderingContext->getTemplatePaths()->setTemplateRootPaths($renderingOptions['templateRootPaths']);
+        $renderingContext->getTemplatePaths()->setLayoutRootPaths($renderingOptions['layoutRootPaths']);
+        $renderingContext->getTemplatePaths()->setPartialRootPaths($renderingOptions['partialRootPaths']);
+
+        // Add the renderable object to the template variables and use the
+        // configured variable name
+        $renderingContext->getVariableProvider()->add($renderingOptions['renderableNameInTemplate'], $renderable);
+
+        // Render the renderable.
+        if (isset($renderingOptions['templatePathAndFilename'])) {
+            $renderingContext->getTemplatePaths()->setTemplatePathAndFilename($renderingOptions['templatePathAndFilename']);
+            $output = $this->render();
+        } else {
+            // Use the *type* of the renderable as template name
+            $output = $this->render($renderable->getType());
+        }
+
+        return $this->renderPreviewMode($output, $renderable);
+    }
+
+    /**
+     * Wrap every renderable with a span with a identifier path data attribute.
+     *
+     * @param string $output
+     * @param RootRenderableInterface $renderable
+     * @return string
+     * @internal
+     */
+    protected function renderPreviewMode(string $output, RootRenderableInterface $renderable): string
+    {
+        $renderingOptions = $this->formRuntime->getRenderingOptions();
+        $previewMode = isset($renderingOptions['previewMode']) && $renderingOptions['previewMode'] === true;
+        if ($previewMode) {
+            $path = $renderable->getIdentifier();
+            if ($renderable instanceof RenderableInterface) {
+                while ($renderable = $renderable->getParentRenderable()) {
+                    $path = $renderable->getIdentifier() . '/' . $path;
+                }
+            }
+            $output = sprintf('<span data-element-identifier-path="%s">%s</span>', $path, $output);
+        }
+        return $output;
+    }
+}
diff --git a/typo3/sysext/form/Classes/PostProcess/AbstractPostProcessor.php b/typo3/sysext/form/Classes/PostProcess/AbstractPostProcessor.php
deleted file mode 100644
index 1a0f0366b91d16b57a80890a6498c8a09a91cd6d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/PostProcess/AbstractPostProcessor.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\PostProcess;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * The mail post processor
- */
-abstract class AbstractPostProcessor
-{
-    /**
-     * @var \TYPO3\CMS\Form\Mvc\Controller\ControllerContext
-     */
-    protected $controllerContext;
-
-    /**
-     * Set the current controller context
-     *
-     * @param \TYPO3\CMS\Form\Mvc\Controller\ControllerContext $controllerContext
-     * @return void
-     */
-    public function setControllerContext(\TYPO3\CMS\Form\Mvc\Controller\ControllerContext $controllerContext)
-    {
-        $this->controllerContext = $controllerContext;
-    }
-}
diff --git a/typo3/sysext/form/Classes/PostProcess/MailPostProcessor.php b/typo3/sysext/form/Classes/PostProcess/MailPostProcessor.php
deleted file mode 100644
index 1cf9517a001936fc0aed793b2aba6035745a7a91..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/PostProcess/MailPostProcessor.php
+++ /dev/null
@@ -1,566 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\PostProcess;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Mail\Rfc822AddressesParser;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Core\Utility\MailUtility;
-use TYPO3\CMS\Core\Utility\MathUtility;
-use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
-use TYPO3\CMS\Form\Utility\FormUtility;
-
-/**
- * The mail post processor
- */
-class MailPostProcessor extends AbstractPostProcessor implements PostProcessorInterface
-{
-    /**
-     * Constant for localization
-     *
-     * @var string
-     */
-    const LOCALISATION_OBJECT_NAME = 'tx_form_view_mail';
-
-    /**
-     * @var \TYPO3\CMS\Extbase\Object\ObjectManager
-     */
-    protected $objectManager;
-
-    /**
-     * @var \TYPO3\CMS\Form\Utility\SessionUtility
-     */
-    protected $sessionUtility;
-
-    /**
-     * @var FormUtility
-     */
-    protected $formUtility;
-
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Model\Element
-     */
-    protected $form;
-
-    /**
-     * @var array
-     */
-    protected $typoScript;
-
-    /**
-     * @var \TYPO3\CMS\Core\Mail\MailMessage
-     */
-    protected $mailMessage;
-
-    /**
-     * @var string
-     */
-    protected $htmlMailTemplatePath = 'Html';
-
-    /**
-     * @var string
-     */
-    protected $plaintextMailTemplatePath = 'Plain';
-
-    /**
-     * @var array
-     */
-    protected $dirtyHeaders = [];
-
-    /**
-     * @param \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager
-     * @return void
-     */
-    public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManager $objectManager)
-    {
-        $this->objectManager = $objectManager;
-    }
-
-    /**
-     * @param \TYPO3\CMS\Form\Utility\SessionUtility $sessionUtility
-     * @return void
-     */
-    public function injectSessionUtility(\TYPO3\CMS\Form\Utility\SessionUtility $sessionUtility)
-    {
-        $this->sessionUtility = $sessionUtility;
-    }
-
-    /**
-     * Constructor
-     *
-     * @param \TYPO3\CMS\Form\Domain\Model\Element $form Form domain model
-     * @param array $typoScript Post processor TypoScript settings
-     */
-    public function __construct(\TYPO3\CMS\Form\Domain\Model\Element $form, array $typoScript)
-    {
-        $this->form = $form;
-        $this->typoScript = $typoScript;
-        $this->mailMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Mail\MailMessage::class);
-        $this->setTemplatePaths();
-    }
-
-    /**
-     * The main method called by the post processor
-     *
-     * Configures the mail message
-     *
-     * @return string HTML message from this processor
-     */
-    public function process()
-    {
-        $this->formUtility = FormUtility::create($this->controllerContext->getConfiguration());
-        $this->setSubject();
-        $this->setFrom();
-        $this->setTo();
-        $this->setCc();
-        $this->setReplyTo();
-        $this->setPriority();
-        $this->setOrganization();
-        $this->setHtmlContent();
-        $this->setPlainContent();
-        $this->addAttachmentsFromSession();
-        $this->send();
-        return $this->render();
-    }
-
-    /**
-     * Sets the subject of the mail message
-     *
-     * If not configured, it will use a default setting
-     *
-     * @return void
-     */
-    protected function setSubject()
-    {
-        if (isset($this->typoScript['subject'])) {
-            $subject = $this->formUtility->renderItem(
-                $this->typoScript['subject.'],
-                $this->typoScript['subject']
-            );
-        } elseif ($this->getTypoScriptValueFromIncomingData('subjectField') !== null) {
-            $subject = $this->getTypoScriptValueFromIncomingData('subjectField');
-        } else {
-            $subject = 'Formmail on ' . GeneralUtility::getIndpEnv('HTTP_HOST');
-        }
-
-        $subject = $this->sanitizeHeaderString($subject);
-        $this->mailMessage->setSubject($subject);
-    }
-
-    /**
-     * Sets the sender of the mail message
-     *
-     * Mostly the sender is a combination of the name and the email address
-     *
-     * @return void
-     */
-    protected function setFrom()
-    {
-        if (isset($this->typoScript['senderEmail'])) {
-            $fromEmail = $this->formUtility->renderItem(
-                $this->typoScript['senderEmail.'],
-                $this->typoScript['senderEmail']
-            );
-        } elseif ($this->getTypoScriptValueFromIncomingData('senderEmailField') !== null) {
-            $fromEmail = $this->getTypoScriptValueFromIncomingData('senderEmailField');
-        } else {
-            $fromEmail = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress'];
-        }
-        if (!GeneralUtility::validEmail($fromEmail)) {
-            $fromEmail = MailUtility::getSystemFromAddress();
-        }
-        if (isset($this->typoScript['senderName'])) {
-            $fromName = $this->formUtility->renderItem(
-                $this->typoScript['senderName.'],
-                $this->typoScript['senderName']
-            );
-        } elseif ($this->getTypoScriptValueFromIncomingData('senderNameField') !== null) {
-            $fromName = $this->getTypoScriptValueFromIncomingData('senderNameField');
-        } else {
-            $fromName = $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromName'];
-        }
-        $fromName = $this->sanitizeHeaderString($fromName);
-        if (!empty($fromName)) {
-            $from = [$fromEmail => $fromName];
-        } else {
-            $from = $fromEmail;
-        }
-        $this->mailMessage->setFrom($from);
-    }
-
-    /**
-     * Filter input-string for valid email addresses
-     *
-     * @param string $emails If this is a string, it will be checked for one or more valid email addresses.
-     * @return array List of valid email addresses
-     */
-    protected function filterValidEmails($emails)
-    {
-        if (!is_string($emails)) {
-            // No valid addresses - empty list
-            return [];
-        }
-
-        /** @var $addressParser Rfc822AddressesParser */
-        $addressParser = GeneralUtility::makeInstance(Rfc822AddressesParser::class, $emails);
-        $addresses = $addressParser->parseAddressList();
-
-        $validEmails = [];
-        foreach ($addresses as $address) {
-            $fullAddress = $address->mailbox . '@' . $address->host;
-            if (GeneralUtility::validEmail($fullAddress)) {
-                if ($address->personal) {
-                    $validEmails[$fullAddress] = $address->personal;
-                } else {
-                    $validEmails[] = $fullAddress;
-                }
-            }
-        }
-        return $validEmails;
-    }
-
-    /**
-     * Adds the receiver of the mail message when configured
-     *
-     * Checks the address if it is a valid email address
-     *
-     * @return void
-     */
-    protected function setTo()
-    {
-        $emails = $this->formUtility->renderItem(
-            $this->typoScript['recipientEmail.'],
-            $this->typoScript['recipientEmail']
-        );
-        $validEmails = $this->filterValidEmails($emails);
-        if (!empty($validEmails)) {
-            $this->mailMessage->setTo($validEmails);
-        }
-    }
-
-    /**
-     * Adds the carbon copy receiver of the mail message when configured
-     *
-     * Checks the address if it is a valid email address
-     *
-     * @return void
-     */
-    protected function setCc()
-    {
-        $emails = $this->formUtility->renderItem(
-            $this->typoScript['ccEmail.'],
-            $this->typoScript['ccEmail']
-        );
-        $validEmails = $this->filterValidEmails($emails);
-        if (!empty($validEmails)) {
-            $this->mailMessage->setCc($validEmails);
-        }
-    }
-
-    /**
-     * Adds the reply to header of the mail message when configured
-     *
-     * Checks the address if it is a valid email address
-     *
-     * @return void
-     */
-    protected function setReplyTo()
-    {
-        if (isset($this->typoScript['replyToEmail'])) {
-            $emails = $this->formUtility->renderItem(
-                $this->typoScript['replyToEmail.'],
-                $this->typoScript['replyToEmail']
-            );
-        } elseif ($this->getTypoScriptValueFromIncomingData('replyToEmailField') !== null) {
-            $emails = $this->getTypoScriptValueFromIncomingData('replyToEmailField');
-        }
-        $validEmails = $this->filterValidEmails($emails);
-        if (!empty($validEmails)) {
-            $this->mailMessage->setReplyTo($validEmails);
-        }
-    }
-
-    /**
-     * Set the priority of the mail message
-     *
-     * When not in settings, the value will be 3. If the priority is configured,
-     * but too big, it will be set to 5, which means very low.
-     *
-     * @return void
-     */
-    protected function setPriority()
-    {
-        $priority = 3;
-        if (isset($this->typoScript['priority'])) {
-            $priorityFromTs = $this->formUtility->renderItem(
-                $this->typoScript['priority.'],
-                $this->typoScript['priority']
-            );
-        }
-        if (!empty($priorityFromTs)) {
-            $priority = MathUtility::forceIntegerInRange($priorityFromTs, 1, 5);
-        }
-        $this->mailMessage->setPriority($priority);
-    }
-
-    /**
-     * Add a text header to the mail header of the type Organization
-     *
-     * Sanitizes the header string when necessary
-     *
-     * @return void
-     */
-    protected function setOrganization()
-    {
-        if (isset($this->typoScript['organization'])) {
-            $organization = $this->formUtility->renderItem(
-                $this->typoScript['organization.'],
-                $this->typoScript['organization']
-            );
-        }
-        if (!empty($organization)) {
-            $organization = $this->sanitizeHeaderString($organization);
-            $this->mailMessage->getHeaders()->addTextHeader('Organization', $organization);
-        }
-    }
-
-    /**
-     * Set the default character set used
-     *
-     * Respect formMailCharset if it was set, otherwise use metaCharset for mail
-     * if different than utf-8
-     *
-     * @return void
-     */
-    protected function setCharacterSet()
-    {
-        $characterSet = null;
-        if ($GLOBALS['TSFE']->config['config']['formMailCharset']) {
-            $characterSet = $GLOBALS['TSFE']->csConvObj->parse_charset($GLOBALS['TSFE']->config['config']['formMailCharset']);
-        } elseif ($GLOBALS['TSFE']->metaCharset !== 'utf-8') {
-            $characterSet = $GLOBALS['TSFE']->metaCharset;
-        }
-        if ($characterSet) {
-            $this->mailMessage->setCharset($characterSet);
-        }
-    }
-
-    /**
-     * Add the HTML content
-     *
-     * Add a MimePart of the type text/html to the message.
-     *
-     * @return void
-     */
-    protected function setHtmlContent()
-    {
-        $htmlContent = $this->getView($this->htmlMailTemplatePath)->render();
-        $this->mailMessage->setBody($htmlContent, 'text/html');
-    }
-
-    /**
-     * Add the plain content
-     *
-     * Add a MimePart of the type text/plain to the message.
-     *
-     * @return void
-     */
-    protected function setPlainContent()
-    {
-        $plainContent = $this->getView($this->plaintextMailTemplatePath, 'Plain')->render();
-        $this->mailMessage->addPart($plainContent, 'text/plain');
-    }
-
-    /**
-     * Sends the mail.
-     * Sending the mail requires the recipient and message to be set.
-     *
-     * @return void
-     */
-    protected function send()
-    {
-        if ($this->mailMessage->getTo() && $this->mailMessage->getBody()) {
-            $this->mailMessage->send();
-        }
-    }
-
-    /**
-     * Render the message after trying to send the mail
-     *
-     * @return string HTML message from the mail view
-     */
-    protected function render()
-    {
-        if ($this->mailMessage->isSent()) {
-            $output = $this->renderMessage('success');
-        } else {
-            $output = $this->renderMessage('error');
-        }
-        return $output;
-    }
-
-    /**
-     * Checks string for suspicious characters
-     *
-     * @param string $string String to check
-     * @return string Valid or empty string
-     */
-    protected function sanitizeHeaderString($string)
-    {
-        $pattern = '/[\\r\\n\\f\\e]/';
-        if (preg_match($pattern, $string) > 0) {
-            $this->dirtyHeaders[] = $string;
-            $string = '';
-        }
-        return $string;
-    }
-
-    /**
-     * Loop through all elements of the session and attach the file
-     * if its a uploaded file
-     *
-     * @return void
-     */
-    protected function addAttachmentsFromSession()
-    {
-        $sessionData = $this->sessionUtility->getSessionData();
-        if (is_array($sessionData)) {
-            foreach ($sessionData as $fieldName => $values) {
-                if (is_array($values)) {
-                    foreach ($values as $file) {
-                        if (isset($file['tempFilename'])) {
-                            if (
-                                is_file($file['tempFilename'])
-                                && GeneralUtility::isAllowedAbsPath($file['tempFilename'])
-                            ) {
-                                $this->mailMessage->attach(\Swift_Attachment::fromPath($file['tempFilename'])->setFilename($file['name']));
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Set the html and plaintext templates
-     *
-     * @return void
-     */
-    protected function setTemplatePaths()
-    {
-        if (
-            isset($this->typoScript['htmlMailTemplatePath'])
-            && $this->typoScript['htmlMailTemplatePath'] !== ''
-        ) {
-            $this->htmlMailTemplatePath = $this->typoScript['htmlMailTemplatePath'];
-        }
-
-        if (
-            isset($this->typoScript['plaintextMailTemplatePath'])
-            && $this->typoScript['plaintextMailTemplatePath'] !== ''
-        ) {
-            $this->plaintextMailTemplatePath = $this->typoScript['plaintextMailTemplatePath'];
-        }
-    }
-
-    /**
-     * Make fluid view instance
-     *
-     * @param string $templateName
-     * @param string $scope
-     * @return \TYPO3\CMS\Fluid\View\StandaloneView
-     */
-    protected function getView($templateName, $scope = 'Html')
-    {
-        $configurationManager = $this->objectManager->get(\TYPO3\CMS\Extbase\Configuration\ConfigurationManager::class);
-        $typoScript = $configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
-        /** @var \TYPO3\CMS\Fluid\View\StandaloneView $view */
-        $view = $this->objectManager->get(\TYPO3\CMS\Fluid\View\StandaloneView::class);
-
-        /* Extend all template root paths to $templateRootPaths/PostProcessor/Mail/$themeName  */
-        foreach ($typoScript['view']['templateRootPaths'] as &$path) {
-            if (substr($path, -1) !== '/') {
-                $path .= '/';
-            }
-            $path .= 'PostProcessor/Mail/' . $this->controllerContext->getConfiguration()->getThemeName();
-        }
-        /* Extend all partial root paths to $partialRootPaths/$themeName/PostProcessor/Mail/$scope/  */
-        foreach ($typoScript['view']['partialRootPaths'] as &$path) {
-            if (substr($path, -1) !== '/') {
-                $path .= '/';
-            }
-            $path .=  $this->controllerContext->getConfiguration()->getThemeName() . '/PostProcessor/Mail/' . $scope . '/';
-        }
-        $view->setLayoutRootPaths($typoScript['view']['layoutRootPaths']);
-        $view->setTemplateRootPaths($typoScript['view']['templateRootPaths']);
-        $view->setPartialRootPaths($typoScript['view']['partialRootPaths']);
-        $view->setTemplate($templateName);
-        $view->assignMultiple([
-            'model' => $this->form
-        ]);
-        return $view;
-    }
-
-    /**
-     * Render the processor message
-     *
-     * @param string $messageType
-     * @return string
-     */
-    protected function renderMessage($messageType)
-    {
-        return $this->formUtility->renderItem(
-            $this->typoScript['messages.'][$messageType . '.'],
-            $this->typoScript['messages.'][$messageType],
-            $this->getLocalLanguageLabel($messageType)
-        );
-    }
-
-    /**
-     * Get the local language label(s) for the message
-     * In some cases this method will be override by rule class
-     *
-     * @param string $type The type
-     * @return string The local language message label
-     */
-    protected function getLocalLanguageLabel($type = '')
-    {
-        $label = static::LOCALISATION_OBJECT_NAME . '.' . $type;
-        $message = LocalizationUtility::translate($label, 'form');
-        return $message;
-    }
-
-    /**
-     * Determines user submitted data from a field
-     * that has been defined as TypoScript property.
-     *
-     * @param string $propertyName
-     * @return NULL|mixed
-     */
-    protected function getTypoScriptValueFromIncomingData($propertyName)
-    {
-        if (empty($this->typoScript[$propertyName])) {
-            return null;
-        }
-
-        $propertyValue = $this->typoScript[$propertyName];
-        $incomingData = $this->controllerContext->getValidationElement();
-        if (!$incomingData->hasIncomingField($propertyValue)) {
-            return null;
-        }
-
-        return $incomingData->getIncomingField($propertyValue);
-    }
-}
diff --git a/typo3/sysext/form/Classes/PostProcess/PostProcessor.php b/typo3/sysext/form/Classes/PostProcess/PostProcessor.php
deleted file mode 100644
index 1fb2f5227d21fdaff4392b150dbd344dc5f776af..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/PostProcess/PostProcessor.php
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\PostProcess;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\ArrayUtility;
-
-/**
- * The post processor
- */
-class PostProcessor extends AbstractPostProcessor
-{
-    /**
-     * @var \TYPO3\CMS\Extbase\Object\ObjectManager
-     */
-    protected $objectManager;
-
-    /**
-     * @var array
-     */
-    protected $postProcessorTypoScript;
-
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Model\Element $form
-     */
-    protected $form;
-
-    /**
-     * @param \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager
-     * @return void
-     */
-    public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManager $objectManager)
-    {
-        $this->objectManager = $objectManager;
-    }
-
-    /**
-     * Constructor
-     *
-     * @param \TYPO3\CMS\Form\Domain\Model\Element $form
-     * @param array $postProcessorTypoScript Post processor TypoScript settings
-     */
-    public function __construct(\TYPO3\CMS\Form\Domain\Model\Element $form, array $postProcessorTypoScript)
-    {
-        $this->form = $form;
-        $this->postProcessorTypoScript = $postProcessorTypoScript;
-    }
-
-    /**
-     * The main method called by the controller
-     *
-     * Iterates over the configured post processors and calls them with their
-     * own settings
-     *
-     * @return string HTML messages from the called processors
-     */
-    public function process()
-    {
-        $html = '';
-
-        if (is_array($this->postProcessorTypoScript)) {
-            $keys = ArrayUtility::filterAndSortByNumericKeys($this->postProcessorTypoScript);
-
-            foreach ($keys as $key) {
-                if (!(int)$key || strpos($key, '.') !== false) {
-                    continue;
-                }
-                $className = false;
-                $processorName = $this->postProcessorTypoScript[$key];
-                $processorArguments = [];
-                if (isset($this->postProcessorTypoScript[$key . '.'])) {
-                    $processorArguments = $this->postProcessorTypoScript[$key . '.'];
-                }
-
-                if (class_exists($processorName, true)) {
-                    $className = $processorName;
-                } else {
-                    $classNameExpanded = 'TYPO3\\CMS\\Form\\PostProcess\\' . ucfirst(strtolower($processorName)) . 'PostProcessor';
-                    if (class_exists($classNameExpanded, true)) {
-                        $className = $classNameExpanded;
-                    }
-                }
-                if ($className !== false) {
-                    $processor = $this->objectManager->get($className, $this->form, $processorArguments);
-                    if ($processor instanceof PostProcessorInterface) {
-                        $processor->setControllerContext($this->controllerContext);
-                        $html .= $processor->process();
-                    }
-                }
-            }
-        }
-
-        return $html;
-    }
-}
diff --git a/typo3/sysext/form/Classes/PostProcess/PostProcessorInterface.php b/typo3/sysext/form/Classes/PostProcess/PostProcessorInterface.php
deleted file mode 100644
index bbbbc7d898658cc063941c6a2ea9586852eb13a5..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/PostProcess/PostProcessorInterface.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\PostProcess;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Interface for post-processors
- */
-interface PostProcessorInterface
-{
-    /**
-     * Constructor
-     *
-     * @param \TYPO3\CMS\Form\Domain\Model\Element $form Form domain model
-     * @param array $typoScript Post processor TypoScript settings
-     */
-    public function __construct(\TYPO3\CMS\Form\Domain\Model\Element $form, array $typoScript);
-
-    /**
-     * Set the current controller context
-     *
-     * @param \TYPO3\CMS\Form\Mvc\Controller\ControllerContext $controllerContext
-     * @return void
-     */
-    public function setControllerContext(\TYPO3\CMS\Form\Mvc\Controller\ControllerContext $controllerContext);
-
-    /**
-     * The main method called by the post processor
-     *
-     * @return string The post processing HTML
-     */
-    public function process();
-}
diff --git a/typo3/sysext/form/Classes/PostProcess/RedirectPostProcessor.php b/typo3/sysext/form/Classes/PostProcess/RedirectPostProcessor.php
deleted file mode 100644
index 58f7083997b1bbad346e3e00dc11839870c3002a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/PostProcess/RedirectPostProcessor.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\PostProcess;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * The redirect post-processor
- */
-class RedirectPostProcessor extends AbstractPostProcessor implements PostProcessorInterface
-{
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Model\Element
-     */
-    protected $form;
-
-    /**
-     * @var array
-     */
-    protected $typoScript;
-
-    /**
-     * @var string
-     */
-    protected $destination;
-
-    /**
-     * Constructor
-     *
-     * @param \TYPO3\CMS\Form\Domain\Model\Element $form Form domain model
-     * @param array $typoScript Post processor TypoScript settings
-     */
-    public function __construct(\TYPO3\CMS\Form\Domain\Model\Element $form, array $typoScript)
-    {
-        $this->form = $form;
-        $this->typoScript = $typoScript;
-    }
-
-    /**
-     * The main method called by the post processor
-     *
-     * @return string HTML message from this processor
-     */
-    public function process()
-    {
-        $this->setDestination();
-        $this->render();
-    }
-
-    /**
-     * Sets the redirect destination
-     *
-     * @return void
-     */
-    protected function setDestination()
-    {
-        $this->destination = '';
-        if ($this->typoScript['destination']) {
-            $urlConf = ['parameter' => $this->typoScript['destination']];
-            $this->destination = $GLOBALS['TSFE']->cObj->typoLink_URL($urlConf);
-        }
-    }
-
-    /**
-     * Redirect to a destination
-     *
-     * @return void
-     */
-    protected function render()
-    {
-        \TYPO3\CMS\Core\Utility\HttpUtility::redirect($this->destination);
-        return;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Service/TranslationService.php b/typo3/sysext/form/Classes/Service/TranslationService.php
new file mode 100644
index 0000000000000000000000000000000000000000..b975b03d38b3c942a847cb5025bf08db80b14c7d
--- /dev/null
+++ b/typo3/sysext/form/Classes/Service/TranslationService.php
@@ -0,0 +1,508 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Service;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Localization\Locales;
+use TYPO3\CMS\Core\Localization\LocalizationFactory;
+use TYPO3\CMS\Core\SingletonInterface;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\Utility\ArrayUtility;
+use TYPO3\CMS\Form\Domain\Model\FormElements\FormElementInterface;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+use TYPO3\CMS\Lang\LanguageService;
+
+/**
+ * Advanced translations
+ * This class is subjected to change.
+ * **Do NOT subclass**
+ *
+ * Scope: frontend / backend
+ * @internal
+ */
+class TranslationService implements SingletonInterface
+{
+
+    /**
+     * Local Language content
+     *
+     * @var array
+     */
+    protected $LOCAL_LANG = [];
+
+    /**
+     * Contains those LL keys, which have been set to (empty) in TypoScript.
+     * This is necessary, as we cannot distinguish between a nonexisting
+     * translation and a label that has been cleared by TS.
+     * In both cases ['key'][0]['target'] is "".
+     *
+     * @var array
+     */
+    protected $LOCAL_LANG_UNSET = [];
+
+    /**
+     * Key of the language to use
+     *
+     * @var string
+     */
+    protected $languageKey = null;
+
+    /**
+     * Pointer to alternative fall-back language to use
+     *
+     * @var array
+     */
+    protected $alternativeLanguageKeys = [];
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
+     */
+    protected $configurationManager = null;
+
+    /**
+     * Return TranslationService as singleton
+     *
+     * @return TranslationService
+     * @internal
+     */
+    public static function getInstance()
+    {
+        return GeneralUtility::makeInstance(ObjectManager::class)->get(self::class);
+    }
+
+    /**
+     * Returns the localized label of the LOCAL_LANG key, $key.
+     *
+     * @param mixed $key The key from the LOCAL_LANG array for which to return the value.
+     * @param array $arguments the arguments of the extension, being passed over to vsprintf
+     * @param string $locallangPathAndFilename
+     * @param string $language
+     * @param mixed $defaultValue
+     * @return mixed The value from LOCAL_LANG or $defaultValue if no translation was found.
+     * @internal
+     */
+    public function translate(
+        $key,
+        array $arguments = null,
+        string $locallangPathAndFilename = null,
+        string $language = null,
+        $defaultValue = ''
+    ) {
+        $value = null;
+        $key = (string)$key;
+
+        if ($locallangPathAndFilename) {
+            $key = $locallangPathAndFilename . ':' . $key;
+        }
+
+        $keyParts = explode(':', $key);
+        if (GeneralUtility::isFirstPartOfStr($key, 'LLL:')) {
+            $locallangPathAndFilename = $keyParts[1] . ':' . $keyParts[2];
+            $key = $keyParts[3];
+        } elseif (GeneralUtility::isFirstPartOfStr($key, 'EXT:')) {
+            $locallangPathAndFilename = $keyParts[0] . ':' . $keyParts[1];
+            $key = $keyParts[2];
+        } else {
+            if (count($keyParts) === 2) {
+                $locallangPathAndFilename = $keyParts[0];
+                $key = $keyParts[1];
+            }
+        }
+
+        if ($language) {
+            $this->languageKey = $language;
+        }
+
+        $this->initializeLocalization($locallangPathAndFilename);
+
+        // The "from" charset of csConv() is only set for strings from TypoScript via _LOCAL_LANG
+        if (!empty($this->LOCAL_LANG[$this->languageKey][$key][0]['target'])
+            || isset($this->LOCAL_LANG_UNSET[$this->languageKey][$key])
+        ) {
+            // Local language translation for key exists
+            $value = $this->LOCAL_LANG[$this->languageKey][$key][0]['target'];
+        } elseif (!empty($this->alternativeLanguageKeys)) {
+            $languages = array_reverse($this->alternativeLanguageKeys);
+            foreach ($languages as $language) {
+                if (!empty($this->LOCAL_LANG[$language][$key][0]['target'])
+                    || isset($this->LOCAL_LANG_UNSET[$language][$key])
+                ) {
+                    // Alternative language translation for key exists
+                    $value = $this->LOCAL_LANG[$language][$key][0]['target'];
+                    break;
+                }
+            }
+        }
+
+        if ($value === null && (!empty($this->LOCAL_LANG['default'][$key][0]['target'])
+            || isset($this->LOCAL_LANG_UNSET['default'][$key]))
+        ) {
+            // Default language translation for key exists
+            // No charset conversion because default is English and thereby ASCII
+            $value = $this->LOCAL_LANG['default'][$key][0]['target'];
+        }
+
+        if (is_array($arguments) && $value !== null) {
+            $value = vsprintf($value, $arguments);
+        } else {
+            if (empty($value)) {
+                $value = $defaultValue;
+            }
+        }
+
+        return $value;
+    }
+
+    /**
+     * Recursively translate values.
+     *
+     * @param array $array
+     * @param string $translationFile
+     * @return array the modified array
+     * @internal
+     */
+    public function translateValuesRecursive(array $array, string $translationFile = null): array
+    {
+        $result = $array;
+        foreach ($result as $key => $value) {
+            if (is_array($value)) {
+                $result[$key] = $this->translateValuesRecursive($value, $translationFile);
+            } else {
+                $result[$key] = $this->translate($value, null, $translationFile, null, $value);
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * @param FormRuntime $formRuntime
+     * @param string $finisherIdentifier
+     * @param string $optionKey
+     * @param string $optionValue
+     * @param array $renderingOptions
+     * @return string
+     * @throws \InvalidArgumentException
+     * @api
+     */
+    public function translateFinisherOption(
+        FormRuntime $formRuntime,
+        string $finisherIdentifier,
+        string $optionKey,
+        string $optionValue,
+        array $renderingOptions = []
+    ): string {
+        if (empty($finisherIdentifier)) {
+            throw new \InvalidArgumentException('The argument "finisherIdentifier" is empty', 1476216059);
+        }
+        if (empty($optionKey)) {
+            throw new \InvalidArgumentException('The argument "optionKey" is empty', 1476216060);
+        }
+
+        $finisherIdentifier = preg_replace('/Finisher$/', '', $finisherIdentifier);
+        $translationFile = $renderingOptions['translationFile'];
+        if (isset($renderingOptions['translatePropertyValueIfEmpty'])) {
+            $translatePropertyValueIfEmpty = (bool)$renderingOptions['translatePropertyValueIfEmpty'];
+        } else {
+            $translatePropertyValueIfEmpty = true;
+        }
+
+        if (empty($optionValue) && !$translatePropertyValueIfEmpty) {
+            return $optionValue;
+        }
+
+        $language = null;
+        if (isset($renderingOptions['language'])) {
+            $language = $renderingOptions['language'];
+        }
+
+        $translationKeyChain = [
+            sprintf('%s:%s.finisher.%s.%s', $translationFile, $formRuntime->getIdentifier(), $finisherIdentifier, $optionKey),
+            sprintf('%s:finisher.%s.%s', $translationFile, $finisherIdentifier, $optionKey)
+        ];
+        $translatedValue = $this->processTranslationChain($translationKeyChain, $language);
+        $translatedValue = (empty($translatedValue)) ? $optionValue : $translatedValue;
+
+        return $translatedValue;
+    }
+
+    /**
+     * @param RootRenderableInterface $element
+     * @param string $property
+     * @param FormRuntime $formRuntime
+     * @return string|array
+     * @throws \InvalidArgumentException
+     * @internal
+     */
+    public function translateFormElementValue(
+        RootRenderableInterface $element,
+        string $property,
+        FormRuntime $formRuntime
+    ) {
+        if (empty($property)) {
+            throw new \InvalidArgumentException('The argument "property" is empty', 1476216007);
+        }
+
+        $propertyType = 'properties';
+        $renderingOptions = $element->getRenderingOptions();
+
+        if ($property === 'label') {
+            $defaultValue = $element->getLabel();
+        } else {
+            if ($element instanceof FormElementInterface) {
+                $defaultValue = ArrayUtility::getValueByPath($element->getProperties(), $property);
+            } else {
+                $propertyType = 'renderingOptions';
+                $defaultValue = ArrayUtility::getValueByPath($renderingOptions, $property);
+            }
+        }
+
+        if (isset($renderingOptions['translation']['translatePropertyValueIfEmpty'])) {
+            $translatePropertyValueIfEmpty = $renderingOptions['translation']['translatePropertyValueIfEmpty'];
+        } else {
+            $translatePropertyValueIfEmpty = true;
+        }
+
+        if (empty($defaultValue) && !$translatePropertyValueIfEmpty) {
+            return $defaultValue;
+        }
+
+        $defaultValue = empty($defaultValue) ? '' : $defaultValue;
+        $translationFile = $renderingOptions['translation']['translationFile'];
+
+        $language = null;
+        if (isset($renderingOptions['translation']['language'])) {
+            $language = $renderingOptions['translation']['language'];
+        }
+        $translationKeyChain = [];
+        if ($property === 'options' && is_array($defaultValue)) {
+            foreach ($defaultValue as $optionValue => &$optionLabel) {
+                $translationKeyChain = [
+                    sprintf('%s:%s.element.%s.%s.%s.%s', $translationFile, $formRuntime->getIdentifier(), $element->getIdentifier(), $propertyType, $property, $optionValue),
+                    sprintf('%s:element.%s.%s.%s.%s', $translationFile, $element->getIdentifier(), $propertyType, $property, $optionValue)
+                ];
+                $translatedValue = $this->processTranslationChain($translationKeyChain, $language);
+                $optionLabel = (empty($translatedValue)) ? $optionLabel : $translatedValue;
+            }
+            $translatedValue = $defaultValue;
+        } else {
+            $translationKeyChain = [
+                sprintf('%s:%s.element.%s.%s.%s', $translationFile, $formRuntime->getIdentifier(), $element->getIdentifier(), $propertyType, $property),
+                sprintf('%s:element.%s.%s.%s', $translationFile, $element->getIdentifier(), $propertyType, $property),
+                sprintf('%s:element.%s.%s.%s', $translationFile, $element->getType(), $propertyType, $property),
+            ];
+            $translatedValue = $this->processTranslationChain($translationKeyChain, $language);
+            $translatedValue = (empty($translatedValue)) ? $defaultValue : $translatedValue;
+        }
+
+        return $translatedValue;
+    }
+
+    /**
+     * @param string $languageKey
+     * @internal
+     */
+    public function setLanguage(string $languageKey)
+    {
+        $this->languageKey = $languageKey;
+    }
+
+    /**
+     * @return string
+     * @internal
+     */
+    public function getLanguage(): string
+    {
+        return $this->languageKey;
+    }
+
+    /**
+     * @param array $translationKeyChain
+     * @param string $language
+     * @return string|null
+     */
+    protected function processTranslationChain(array $translationKeyChain, string $language = null)
+    {
+        $translatedValue = null;
+        foreach ($translationKeyChain as $translationKey) {
+            $translatedValue = $this->translate($translationKey, null, null, $language);
+            if (!empty($translatedValue)) {
+                break;
+            }
+        }
+        return $translatedValue;
+    }
+
+    /**
+     * @param string $locallangPathAndFilename
+     * @return void
+     */
+    protected function initializeLocalization(string $locallangPathAndFilename)
+    {
+        if (empty($this->languageKey)) {
+            $this->setLanguageKeys();
+        }
+
+        if (!empty($locallangPathAndFilename)) {
+            /** @var $languageFactory LocalizationFactory */
+            $languageFactory = GeneralUtility::makeInstance(LocalizationFactory::class);
+
+            $this->LOCAL_LANG = $languageFactory->getParsedData($locallangPathAndFilename, $this->languageKey, 'utf-8');
+
+            foreach ($this->alternativeLanguageKeys as $language) {
+                $tempLL = $languageFactory->getParsedData($locallangPathAndFilename, $language, 'utf-8');
+                if ($this->languageKey !== 'default' && isset($tempLL[$language])) {
+                    $this->LOCAL_LANG[$language] = $tempLL[$language];
+                }
+            }
+        }
+        $this->loadTypoScriptLabels();
+    }
+
+    /**
+     * Sets the currently active language/language_alt keys.
+     * Default values are "default" for language key and "" for language_alt key.
+     *
+     * @return void
+     */
+    protected function setLanguageKeys()
+    {
+        $this->languageKey = 'default';
+
+        $this->alternativeLanguageKeys = [];
+        if (TYPO3_MODE === 'FE') {
+            if (isset($this->getTypoScriptFrontendController()->config['config']['language'])) {
+                $this->languageKey = $this->getTypoScriptFrontendController()->config['config']['language'];
+                if (isset($this->getTypoScriptFrontendController()->config['config']['language_alt'])) {
+                    $this->alternativeLanguageKeys[] = $this->getTypoScriptFrontendController()->config['config']['language_alt'];
+                } else {
+                    /** @var $locales \TYPO3\CMS\Core\Localization\Locales */
+                    $locales = GeneralUtility::makeInstance(Locales::class);
+                    if (in_array($this->languageKey, $locales->getLocales(), true)) {
+                        foreach ($locales->getLocaleDependencies($this->languageKey) as $language) {
+                            $this->alternativeLanguageKeys[] = $language;
+                        }
+                    }
+                }
+            }
+        } elseif (!empty($GLOBALS['BE_USER']->uc['lang'])) {
+            $this->languageKey = $GLOBALS['BE_USER']->uc['lang'];
+        } elseif (!empty($this->getLanguageService()->lang)) {
+            $this->languageKey = $this->getLanguageService()->lang;
+        }
+    }
+
+    /**
+     * Overwrites labels that are set via TypoScript.
+     * TS locallang labels have to be configured like:
+     * plugin.tx_form._LOCAL_LANG.languageKey.key = value
+     *
+     * @return void
+     */
+    protected function loadTypoScriptLabels()
+    {
+        $frameworkConfiguration = $this->getConfigurationManager()
+            ->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, 'form');
+
+        if (!is_array($frameworkConfiguration['_LOCAL_LANG'])) {
+            return;
+        }
+        $this->LOCAL_LANG_UNSET = [];
+        foreach ($frameworkConfiguration['_LOCAL_LANG'] as $languageKey => $labels) {
+            if (!(is_array($labels) && isset($this->LOCAL_LANG[$languageKey]))) {
+                continue;
+            }
+            foreach ($labels as $labelKey => $labelValue) {
+                if (is_string($labelValue)) {
+                    $this->LOCAL_LANG[$languageKey][$labelKey][0]['target'] = $labelValue;
+                    if ($labelValue === '') {
+                        $this->LOCAL_LANG_UNSET[$languageKey][$labelKey] = '';
+                    }
+                } elseif (is_array($labelValue)) {
+                    $labelValue = $this->flattenTypoScriptLabelArray($labelValue, $labelKey);
+                    foreach ($labelValue as $key => $value) {
+                        $this->LOCAL_LANG[$languageKey][$key][0]['target'] = $value;
+                        if ($value === '') {
+                            $this->LOCAL_LANG_UNSET[$languageKey][$key] = '';
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Flatten TypoScript label array; converting a hierarchical array into a flat
+     * array with the keys separated by dots.
+     *
+     * Example Input:  array('k1' => array('subkey1' => 'val1'))
+     * Example Output: array('k1.subkey1' => 'val1')
+     *
+     * @param array $labelValues Hierarchical array of labels
+     * @param string $parentKey the name of the parent key in the recursion; is only needed for recursion.
+     * @return array flattened array of labels.
+     */
+    protected function flattenTypoScriptLabelArray(array $labelValues, string $parentKey = ''): array
+    {
+        $result = [];
+        foreach ($labelValues as $key => $labelValue) {
+            if (!empty($parentKey)) {
+                $key = $parentKey . '.' . $key;
+            }
+            if (is_array($labelValue)) {
+                $labelValue = $this->flattenTypoScriptLabelArray($labelValue, $key);
+                $result = array_merge($result, $labelValue);
+            } else {
+                $result[$key] = $labelValue;
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * Returns instance of the configuration manager
+     *
+     * @return ConfigurationManagerInterface
+     */
+    protected function getConfigurationManager(): ConfigurationManagerInterface
+    {
+        if ($this->configurationManager !== null) {
+            return $this->configurationManager;
+        }
+
+        $this->configurationManager = GeneralUtility::makeInstance(ObjectManager::class)
+            ->get(ConfigurationManagerInterface::class);
+        return $this->configurationManager;
+    }
+
+    /**
+     * @return LanguageService
+     */
+    protected function getLanguageService(): LanguageService
+    {
+        return $GLOBALS['LANG'];
+    }
+
+    /**
+     * @return TypoScriptFrontendController
+     */
+    protected function getTypoScriptFrontendController(): TypoScriptFrontendController
+    {
+        return $GLOBALS['TSFE'];
+    }
+}
diff --git a/typo3/sysext/form/Classes/Utility/ArrayUtility.php b/typo3/sysext/form/Classes/Utility/ArrayUtility.php
new file mode 100644
index 0000000000000000000000000000000000000000..8790146e8c1ad3c3f772d2cca815c06122bc25dd
--- /dev/null
+++ b/typo3/sysext/form/Classes/Utility/ArrayUtility.php
@@ -0,0 +1,153 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Utility;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Exception\TypeDefinitionNotValidException;
+
+/**
+ * Collection of static array utility functions
+ *
+ * Scope: frontend / backend
+ * @internal
+ */
+class ArrayUtility
+{
+
+    /**
+     * Validates the given $arrayToTest by checking if an element is not in $allowedArrayKeys.
+     *
+     * @param array $arrayToTest
+     * @param array $allowedArrayKeys
+     * @return void
+     * @throws TypeDefinitionNotValidException if an element in $arrayToTest is not in $allowedArrayKeys
+     * @internal
+     */
+    public static function assertAllArrayKeysAreValid(array $arrayToTest, array $allowedArrayKeys)
+    {
+        $notAllowedArrayKeys = array_keys(array_diff_key($arrayToTest, array_flip($allowedArrayKeys)));
+        if (count($notAllowedArrayKeys) !== 0) {
+            throw new TypeDefinitionNotValidException(sprintf('The options "%s" were not allowed (allowed were: "%s")', implode(', ', $notAllowedArrayKeys), implode(', ', $allowedArrayKeys)), 1325697085);
+        }
+    }
+
+    /**
+     * Sort keys from the current nesting level if all keys within the
+     * current nesting level are integers.
+     *
+     * @param array $array
+     * @return array
+     * @internal
+     */
+    public static function sortNumericArrayKeysRecursive(array $array): array
+    {
+        if (count(array_filter(array_keys($array), 'is_string')) === 0) {
+            ksort($array);
+        }
+        foreach ($array as $key => $value) {
+            if (is_array($value) && !empty($value)) {
+                $array[$key] = self::sortNumericArrayKeysRecursive($value);
+            }
+        }
+        return $array;
+    }
+
+    /**
+     * Reindex keys from the current nesting level if all keys within
+     * the current nesting level are integers.
+     *
+     * @param array $array
+     * @return array
+     * @internal
+     */
+    public static function reIndexNumericArrayKeysRecursive(array $array): array
+    {
+        if (count(array_filter(array_keys($array), 'is_string')) === 0) {
+            $array = array_values($array);
+        }
+        foreach ($array as $key => $value) {
+            if (is_array($value) && !empty($value)) {
+                $array[$key] = self::reIndexNumericArrayKeysRecursive($value);
+            }
+        }
+        return $array;
+    }
+
+    /**
+     * Recursively remove keys if their value are NULL.
+     *
+     * @param array $array
+     * @return array the modified array
+     * @internal
+     */
+    public static function removeNullValuesRecursive(array $array): array
+    {
+        $result = $array;
+        foreach ($result as $key => $value) {
+            if (is_array($value)) {
+                $result[$key] = self::removeNullValuesRecursive($value);
+            } elseif ($value === null) {
+                unset($result[$key]);
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * Recursively translate values.
+     *
+     * @param array $array
+     * @return array the modified array
+     * @internal
+     */
+    public static function stripTagsFromValuesRecursive(array $array): array
+    {
+        $result = $array;
+        foreach ($result as $key => $value) {
+            if (is_array($value)) {
+                $result[$key] = self::stripTagsFromValuesRecursive($value);
+            } else {
+                if (!is_bool($value)) {
+                    $result[$key] = strip_tags($value);
+                }
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * Recursively convert 'true' and 'false' strings to boolen values.
+     *
+     * @param array $array
+     * @return array the modified array
+     * @internal
+     */
+    public static function convertBooleanStringsToBooleanRecursive(array $array): array
+    {
+        $result = $array;
+        foreach ($result as $key => $value) {
+            if (is_array($value)) {
+                $result[$key] = self::convertBooleanStringsToBooleanRecursive($value);
+            } else {
+                if ($value === 'true') {
+                    $result[$key] = true;
+                } elseif ($value === 'false') {
+                    $result[$key] = false;
+                }
+            }
+        }
+        return $result;
+    }
+}
diff --git a/typo3/sysext/form/Classes/Utility/ElementCounter.php b/typo3/sysext/form/Classes/Utility/ElementCounter.php
deleted file mode 100644
index 002dabfbb1a22977c6f47e4bf46780f760c60ada..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Utility/ElementCounter.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Utility;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-class ElementCounter implements \TYPO3\CMS\Core\SingletonInterface
-{
-    /**
-     * @var int
-     */
-    protected $elementCounter = 0;
-
-    /**
-     * Raise the element counter by one
-     *
-     * @return int
-     */
-    public function getElementId()
-    {
-        $this->elementCounter++;
-        return $this->elementCounter;
-    }
-}
diff --git a/typo3/sysext/form/Classes/Utility/FormUtility.php b/typo3/sysext/form/Classes/Utility/FormUtility.php
deleted file mode 100644
index a0c49999706bfcfef087c9c6fa53e2b43fa58fd0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Utility/FormUtility.php
+++ /dev/null
@@ -1,283 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Utility;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Form\Domain\Model\Configuration;
-
-/**
- * A utility for the form
- */
-class FormUtility
-{
-    /**
-     * @param Configuration $configuration
-     * @return FormBuilder
-     */
-    public static function create(Configuration $configuration)
-    {
-        /** @var FormBuilder $formBuilder */
-        $formUtility = self::getObjectManager()->get(self::class);
-        $formUtility->setConfiguration($configuration);
-        return $formUtility;
-    }
-
-    /**
-     * @var Configuration
-     */
-    protected $configuration;
-
-    /**
-     * @param Configuration $configuration
-     */
-    public function setConfiguration(Configuration $configuration)
-    {
-        $this->configuration = $configuration;
-    }
-
-    /**
-     * Render TypoScript values
-     * There are different variants. It is possible that the TypoScript
-     * which we want to render looks like this:
-     *
-     * array(
-     *   'message' => 'TEXT',
-     *   'message.' => array(
-     *     'value' => 'blah'
-     *   )
-     * )
-     *
-     * or in "short syntax" (the wizard writes some syntax partly)
-     *
-     * array(
-     *   'message.' => array(
-     *     'value' => 'blah'
-     *   )
-     * )
-     *
-     * or it is simply a string.
-     *
-     * Furthermore we have 2 modes:
-     * - contentelement rendering is allowed
-     * - or contentelement rendering is not allowed
-     *
-     * This method will take care of all scenarios and provide some
-     * fallbacks.
-     * Call this method always in the following way:
-     *
-     * renderItem(
-     *   $typoscript['itemToRender.'],
-     *   $typoscript['itemToRender'],
-     *   $optionalDefaultMessage
-     * )
-     *
-     * You dont have to handle if is $typoscript['itemToRender.'] is
-     * set or not. This function determines this.
-     * This allows us to get the value of a TypoScript construct
-     * without knowing about "short syntax", only a string, a cObject,
-     * if cObject rendering is allowed and so on.
-     *
-     * If contentelement rendering is allowed:
-     *   If $type and $configuration are set
-     *   render as an cObject.
-     *
-     *   If $type is set but $configuration is empty
-     *   only return the value of $type.
-     *
-     *   If $type is empty and $configuration is an array ("short syntax")
-     *   render the $configuration as content type TEXT.
-     *
-     *   If $type is empty and $configuration is a string
-     *   render the value of $configuration like
-     *   10 = TEXT 10.value = $configuration.
-     *
-     *   If $type is empty and $configuration is empty
-     *   return the $defaultMessage.
-     *
-     * If contentelement rendering is not allowed:
-     *   If $type is set but $configuration is empty
-     *   only return the value of $type.
-     *
-     *   If $type is set and $configuration['value'] isset
-     *   return the value of $configuration['value'].
-     *
-     *   If $type is set and $configuration['value'] is not set
-     *   return the value of $defaultMessage.
-     *
-     *   If $type is empty and $configuration['value'] isset
-     *   return the value of $configuration['value'].
-     *
-     *   If $type is empty and $configuration['value'] is not set
-     *   return the value of $defaultMessage.
-     *
-     * @param mixed $configuration a string or a TypoScript array
-     * @param NULL|string $type cObject type or simply a string value
-     * @param string $defaultMessage
-     * @return string
-     */
-    public function renderItem($configuration, $type = null, $defaultMessage = '')
-    {
-        if ($this->configuration->getContentElementRendering()) {
-            $renderedMessage = null;
-            if ($type !== null) {
-                if (is_array($configuration)) {
-                    /* Direct cObject rendering */
-                    $value = $configuration;
-                } else {
-                    /* got only a string, no rendering required */
-                    $renderedMessage = $type;
-                }
-            } else {
-                if ($configuration !== null) {
-                    /* Render the "short syntax"
-                     * The wizard write things like label.value
-                     * The previous version of EXT:form interpreted this
-                     * as a TEXT content object, so we do the same
-                     *  */
-                    $type = 'TEXT';
-                    if (is_array($configuration)) {
-                        $value = $configuration;
-                    } else {
-                        $value['value'] = $configuration;
-                    }
-                } else {
-                    /* return the default message
-                     * If $type === NULL and $configuration === NULL
-                     * return the default message (if set).
-                     * */
-                    $renderedMessage = $defaultMessage;
-                }
-            }
-            if ($renderedMessage === null) {
-                $renderedMessage = $GLOBALS['TSFE']->cObj->cObjGetSingle(
-                    $type,
-                    $value
-                );
-            }
-        } else {
-            if ($type !== null) {
-                if ($configuration !== null) {
-                    /* the wizard write things like label.value = some text
-                     * so we need the handle that, even content object rendering
-                     * is not allowed.
-                     *  */
-                    if (isset($configuration['value'])) {
-                        $renderedMessage = $configuration['value'];
-                    } else {
-                        $renderedMessage = $defaultMessage;
-                    }
-                } else {
-                    // string, no rendering required
-                    $renderedMessage = $type;
-                }
-            } else {
-                $renderedMessage = $defaultMessage;
-                if (
-                    is_array($configuration)
-                    && isset($configuration['value'])
-                ) {
-                    $renderedMessage = $configuration['value'];
-                }
-            }
-        }
-        return $renderedMessage;
-    }
-
-    /**
-     * Render array values recursively as cObjects using the
-     * method renderItem.
-     *
-     * @param array $arrayToRender
-     * @return array
-     */
-    public function renderArrayItems(array &$arrayToRender = [])
-    {
-        foreach ($arrayToRender as $attributeName => &$attributeValue) {
-            $attributeNameWithoutDot = rtrim($attributeName, '.');
-            if (
-                isset($arrayToRender[$attributeNameWithoutDot])
-                && isset($arrayToRender[$attributeNameWithoutDot . '.'])
-            ) {
-                $attributeValue = $this->renderItem(
-                    $arrayToRender[$attributeNameWithoutDot . '.'],
-                    $arrayToRender[$attributeNameWithoutDot]
-                );
-                unset($arrayToRender[$attributeNameWithoutDot . '.']);
-            } elseif (
-                !isset($arrayToRender[$attributeNameWithoutDot])
-                && isset($arrayToRender[$attributeNameWithoutDot . '.'])
-            ) {
-                $this->renderArrayItems($attributeValue);
-            }
-        }
-    }
-
-    /**
-     * If the name is not defined it is automatically generated
-     * using the following syntax: id-{element_counter}
-     * The name attribute will be transformed if it contains some
-     * non allowed characters:
-     * - spaces are changed into hyphens
-     * - remove all characters except a-z A-Z 0-9 _ -
-     *
-     * @param string $name
-     * @return string
-     */
-    public function sanitizeNameAttribute($name)
-    {
-        if (!empty($name)) {
-            // Change spaces into hyphens
-            $name = preg_replace('/\\s/', '-', $name);
-                // Remove non-word characters
-            $name = preg_replace('/[^a-zA-Z0-9_\\-]+/', '', $name);
-        }
-        return $name;
-    }
-
-    /**
-     * If the id is not defined it is automatically generated
-     * using the following syntax: field-{element_counter}
-     * The id attribute will be transformed if it contains some
-     * non allowed characters:
-     * - spaces are changed into hyphens
-     * - if the id start with a integer then transform it to field-{integer}
-     * - remove all characters expect a-z A-Z 0-9 _ - : .
-     *
-     * @param string $id
-     * @return string
-     */
-    public function sanitizeIdAttribute($id)
-    {
-        if (!empty($id)) {
-            // Change spaces into hyphens
-            $attribute = preg_replace('/\\s/', '-', $id);
-            // Change first non-letter to field-
-            if (preg_match('/^([^a-zA-Z]{1})/', $attribute)) {
-                $id = 'field-' . $attribute;
-            }
-            // Remove non-word characters
-            $id = preg_replace('/([^a-zA-Z0-9_:\\-\\.]*)/', '', $id);
-        }
-        return $id;
-    }
-
-    /**
-     * @return \TYPO3\CMS\Extbase\Object\ObjectManager
-     */
-    public static function getObjectManager()
-    {
-        return GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
-    }
-}
diff --git a/typo3/sysext/form/Classes/Utility/SessionUtility.php b/typo3/sysext/form/Classes/Utility/SessionUtility.php
deleted file mode 100644
index 00f9c5ae734a373d327ae4d51b9fdf7149e00325..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Utility/SessionUtility.php
+++ /dev/null
@@ -1,160 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Utility;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\SingletonInterface;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
-
-/**
- * A session utility
- */
-class SessionUtility implements SingletonInterface
-{
-    /**
-     * Session data
-     *
-     * @var array
-     */
-    protected $sessionData = [];
-
-    /**
-     * Prefix for the session
-     *
-     * @var string
-     */
-    protected $formPrefix = '';
-
-    /**
-     * @var TypoScriptFrontendController
-     */
-    protected $frontendController;
-
-    /**
-     * Constructor
-     */
-    public function __construct()
-    {
-        $this->frontendController = $GLOBALS['TSFE'];
-    }
-
-    /**
-     * Store the form input in a session
-     *
-     * @param string $formPrefix
-     * @return void
-     */
-    public function initSession($formPrefix = '')
-    {
-        $this->setFormPrefix($formPrefix);
-        if ($this->frontendController->loginUser) {
-            $this->sessionData = $this->frontendController->fe_user->getKey('user', $this->formPrefix);
-        } else {
-            $this->sessionData = $this->frontendController->fe_user->getKey('ses', $this->formPrefix);
-        }
-    }
-
-    /**
-     * Store the form input in a session
-     *
-     * @return void
-     */
-    public function storeSession()
-    {
-        if ($this->frontendController->loginUser) {
-            $this->frontendController->fe_user->setKey('user', $this->formPrefix, $this->getSessionData());
-        } else {
-            $this->frontendController->fe_user->setKey('ses', $this->formPrefix, $this->getSessionData());
-        }
-        $this->frontendController->storeSessionData();
-    }
-
-    /**
-     * Destroy the session data for the form
-     *
-     * @return void
-     */
-    public function destroySession()
-    {
-        $this->removeFiles();
-        if ($this->frontendController->loginUser) {
-            $this->frontendController->fe_user->setKey('user', $this->formPrefix, null);
-        } else {
-            $this->frontendController->fe_user->setKey('ses', $this->formPrefix, null);
-        }
-        $this->frontendController->storeSessionData();
-    }
-
-    /**
-     * Set the session Data by $key
-     *
-     * @param string $key
-     * @param string $value
-     * @return void
-     */
-    public function setSessionData($key, $value)
-    {
-        $this->sessionData[$key] = $value;
-    }
-
-    /**
-     * Retrieve a member of the $sessionData variable
-     *
-     * If no $key is passed, returns the entire $sessionData array
-     *
-     * @param string $key Parameter to search for
-     * @param mixed $default Default value to use if key not found
-     * @return mixed Returns NULL if key does not exist
-     */
-    public function getSessionData($key = null, $default = null)
-    {
-        if ($key === null) {
-            return $this->sessionData;
-        }
-        return isset($this->sessionData[$key]) ? $this->sessionData[$key] : $default;
-    }
-
-    /**
-     * Set the form prefix
-     *
-     * @param string $formPrefix
-     * @return array
-     */
-    public function setFormPrefix($formPrefix)
-    {
-        $this->formPrefix = $formPrefix;
-    }
-
-    /**
-     * Remove uploaded files from the typo3temp
-     *
-     * @return void
-     */
-    protected function removeFiles()
-    {
-        $sessionData = $this->getSessionData();
-        if (is_array($sessionData)) {
-            foreach ($sessionData as $fieldName => $values) {
-                if (is_array($values)) {
-                    foreach ($values as $file) {
-                        if (isset($file['tempFilename'])) {
-                            GeneralUtility::unlink_tempfile($file['tempFilename']);
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/Utility/TypoScriptToJsonConverter.php b/typo3/sysext/form/Classes/Utility/TypoScriptToJsonConverter.php
deleted file mode 100644
index 6ef9881b0205870c0d76e11ae1f30817b12bdac0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/Utility/TypoScriptToJsonConverter.php
+++ /dev/null
@@ -1,212 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Utility;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\ArrayUtility;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement;
-
-/**
- * Typoscript to JSON converter
- *
- * Takes the incoming TypoScript and converts it to JSON.
- */
-class TypoScriptToJsonConverter
-{
-    protected $registeredElementNames = [
-        'BUTTON',
-        'CHECKBOX',
-        'CHECKBOXGROUP',
-        'FIELDSET',
-        'FILEUPLOAD',
-        'HEADER',
-        'HIDDEN',
-        'OPTGROUP',
-        'OPTION',
-        'PASSWORD',
-        'RADIO',
-        'RADIOGROUP',
-        'RESET',
-        'SELECT',
-        'SUBMIT',
-        'TEXTAREA',
-        'TEXTBLOCK',
-        'TEXTLINE'
-    ];
-
-    /**
-     * @var array
-     */
-    protected $nameMapping = [
-        'checkboxgroup' => 'CheckboxGroup',
-        'radiogroup' => 'RadioGroup',
-    ];
-
-    /**
-     * @var array
-     */
-    protected $validationRules;
-
-    /**
-     * Convert TypoScript string to JSON
-     *
-     * @param array $typoscript TypoScript string containing all configuration for the form
-     * @return TYPO3\CMS\Form\Domain\Model\Json\FormJsonElement|false The JSON for the form
-     */
-    public function convert(array $typoscript)
-    {
-        $this->setValidationRules($typoscript);
-        $jsonObject = $this->createElement('form', $typoscript);
-        return $jsonObject;
-    }
-
-    /**
-     * Create element by loading class
-     * and instantiating the object
-     *
-     * @param string $class Type of element
-     * @param array $arguments Configuration array
-     * @return AbstractJsonElement
-     * @throws \RuntimeException
-     */
-    public function createElement($class, array $arguments = [])
-    {
-        $class = strtolower((string)$class);
-        if (!empty($this->nameMapping[$class])) {
-            $class = $this->nameMapping[$class];
-        }
-        $className = 'TYPO3\\CMS\\Form\\Domain\\Model\Json\\' . ucfirst($class) . 'JsonElement';
-        $this->addValidationRules($arguments);
-
-        if (!class_exists($className)) {
-            throw new \RuntimeException('Class "' . $className . '" does not exist', 1440779351);
-        }
-
-        /** @var $object AbstractJsonElement */
-        $object = GeneralUtility::makeInstance($className);
-        $object->setParameters($arguments);
-        if ($object->childElementsAllowed()) {
-            $this->getChildElementsByIntegerKey($object, $arguments);
-        }
-        return $object;
-    }
-
-    /**
-     * Rendering of a "numerical array" of Form objects from TypoScript
-     * Creates new object for each element found
-     *
-     * @param AbstractJsonElement $parentElement Parent model object
-     * @param array $typoscript Configuration array
-     * @return void
-     */
-    protected function getChildElementsByIntegerKey(AbstractJsonElement $parentElement, array $typoscript)
-    {
-        if (is_array($typoscript)) {
-            $keys = ArrayUtility::filterAndSortByNumericKeys($typoscript);
-            foreach ($keys as $key) {
-                $class = $typoscript[$key];
-                if ((int)$key && strpos($key, '.') === false) {
-                    if (isset($typoscript[$key . '.'])) {
-                        $elementArguments = $typoscript[$key . '.'];
-                    } else {
-                        $elementArguments = [];
-                    }
-                    $this->setElementType($parentElement, $class, $elementArguments);
-                }
-            }
-        }
-    }
-
-    /**
-     * Set the element type of the object
-     *
-     * Checks if the typoscript object is part of the FORM or has a predefined
-     * class for name or header object
-     *
-     * @param AbstractJsonElement $parentElement The parent object
-     * @param string $class A predefined class
-     * @param array $arguments Configuration array
-     * @return void
-     */
-    private function setElementType(AbstractJsonElement $parentElement, $class, array $arguments)
-    {
-        if (in_array($class, $this->registeredElementNames)) {
-            if (strstr($arguments['class'], 'predefined-name')) {
-                $class = 'NAME';
-            }
-            $this->addElement($parentElement, $class, $arguments);
-        }
-    }
-
-    /**
-     * Add child object to this element
-     *
-     * @param AbstractJsonElement $parentElement The parent object
-     * @param string $class Type of element
-     * @param array $arguments Configuration array
-     * @return void
-     */
-    public function addElement(AbstractJsonElement $parentElement, $class, array $arguments)
-    {
-        try {
-            $element = $this->createElement($class, $arguments);
-            $parentElement->addElement($element);
-        } catch (\RuntimeException $exception) {
-            // Catch missing classes or element types
-            // There are elements that can be used the
-            // TypoScript-like declaration, which don't
-            // have a counterpart in the ExtJS wizard.
-        }
-    }
-
-    /**
-     * Set the validation rules
-     *
-     * @param array $typoscript Configuration array
-     * @return void
-     */
-    protected function setValidationRules(array $typoscript)
-    {
-        if (isset($typoscript['rules.']) && is_array($typoscript['rules.'])) {
-            $this->validationRules = $typoscript['rules.'];
-        }
-    }
-
-    /**
-     * Add validation rules to an element if available
-     *
-     * In TypoScript the validation rules belong to the form and are connected
-     * to the elements by name. However, in the wizard, they are added to the
-     * element for usability
-     *
-     * @param array $arguments The element arguments
-     * @return void
-     */
-    protected function addValidationRules(array &$arguments)
-    {
-        if (!empty($this->validationRules) && isset($arguments['name'])) {
-            foreach ($this->validationRules as $key => $ruleName) {
-                if ((int)$key && strpos($key, '.') === false) {
-                    if (isset($this->validationRules[$key . '.'])) {
-                        $ruleConfiguration = $this->validationRules[$key . '.'];
-                        if (isset($ruleConfiguration['element']) && $ruleConfiguration['element'] === $arguments['name']) {
-                            $arguments['validation'][$ruleName] = $ruleConfiguration;
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/View/Wizard/Element/FormWizardElement.php b/typo3/sysext/form/Classes/View/Wizard/Element/FormWizardElement.php
deleted file mode 100644
index c219d9b7173fc4c1906d17b7f40ad2ffe8050528..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/View/Wizard/Element/FormWizardElement.php
+++ /dev/null
@@ -1,230 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\View\Wizard\Element;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Backend\Form\Element\AbstractFormElement;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Core\Utility\StringUtility;
-use TYPO3\CMS\Extbase\Service\TypoScriptService;
-use TYPO3\CMS\Form\Domain\Repository\ContentRepository;
-use TYPO3\CMS\Form\Utility\TypoScriptToJsonConverter;
-
-/**
- * form Wizard widget
- */
-class FormWizardElement extends AbstractFormElement
-{
-    /**
-     * @var array
-     */
-    protected $resultArray;
-
-    /**
-     * Store initialized resultArray
-     */
-    protected function initializeResultArray()
-    {
-        $this->resultArray = parent::initializeResultArray();
-    }
-
-    /**
-     * @return int
-     */
-    protected function getCurrentPageId()
-    {
-        // $this->data used to be globalOptions
-        return (int)$this->data['inlineFirstPid'];
-    }
-
-    /**
-     * @return int
-     */
-    protected function getCurrentUid()
-    {
-        return (int)$this->data['databaseRow']['uid'];
-    }
-
-    /**
-     * @return array
-     */
-    protected function getPlainPageWizardModTsConfigSettingsProperties()
-    {
-        $settings = $this->data['pageTsConfig']['mod.']['wizards.']['form.'];
-        return $this->getTypoScriptService()->convertTypoScriptArrayToPlainArray($settings);
-    }
-
-    /**
-     * Gets the repository object.
-     *
-     * @return ContentRepository
-     */
-    protected function getRepository()
-    {
-        return GeneralUtility::makeInstance(ContentRepository::class);
-    }
-
-    /**
-     * Read and convert the content record to JSON
-     *
-     * @see \TYPO3\CMS\Form\Domain\Repository\ContentRepository::getRecordAsJson
-     * @return TYPO3\CMS\Form\Domain\Model\Json\FormJsonElement|false The JSON object if record exists, FALSE if not
-     */
-    protected function getRecordAsJson()
-    {
-        $json = false;
-        $record = $this->getRepository()->getRecord($this->getCurrentUid(), 'tt_content');
-        if ($record) {
-            $typoscript = $record->getTyposcript();
-            /** @var $converter TypoScriptToJsonConverter */
-            $converter = GeneralUtility::makeInstance(TypoScriptToJsonConverter::class);
-            $json = $converter->convert($typoscript);
-        }
-        return $json;
-    }
-
-    /**
-     * @return string
-     */
-    protected function getAjaxUrl()
-    {
-        /**
-         * @see TYPO3.CMS/src/typo3/sysext/backend/Classes/Form/Element/AbstractFormElement.php:267 for wizard type=popup
-         */
-        $parameterArray = $this->data['parameterArray'];
-        $table = $this->data['tableName'];
-        $fieldName = $this->data['fieldName'];
-        $row = $this->data['databaseRow'];
-        $itemName = $parameterArray['itemFormElName'];
-        // Resolving script filename and setting URL.
-
-        $params = [];
-        $params['fieldConfig'] = $parameterArray['fieldConf'];
-        $params['table'] = $table;
-        $params['uid'] = $row['uid'];
-        $params['pid'] = $row['pid'];
-        $params['field'] = $fieldName;
-
-        $params['formName'] = 'editform';
-        $params['itemName'] = $itemName;
-        $params['hmac'] = GeneralUtility::hmac($params['formName'] . $params['itemName'], 'wizard_js');
-
-        return GeneralUtility::implodeArrayForUrl('', ['P' => $params]);
-    }
-
-    /**
-     * locallang files for return array
-     *
-     * @return array strings
-     */
-    protected function getLocalization()
-    {
-        $wizardLabels = 'EXT:form/Resources/Private/Language/locallang_wizard.xlf';
-        $controllerLabels = 'EXT:form/Resources/Private/Language/locallang.xlf';
-        return [$controllerLabels, $wizardLabels];
-    }
-
-    /**
-     * @param array $settings
-     * @return string
-     */
-    protected function resultAddWizardSettingsJson(array $settings)
-    {
-        $recordJson = $this->getRecordAsJson();
-        $settings['Configuration'] = $recordJson;
-        $settings['ajaxUrl'] = $this->getAjaxUrl();
-        $settingsCommand = 'TYPO3.Form.Wizard.Settings = ' . json_encode($settings) . ';';
-        // enhance global variable for requireJs shim "exports: 'TYPO3.Form.Wizard.Settings'" to work
-        $this->resultArray['additionalJavaScriptPost'][] = ';TYPO3.Form = TYPO3.Form || {Wizard:{}};';
-        $this->resultArray['additionalJavaScriptPost'][] =
-            ';define("TYPO3/CMS/Form/Wizard/Settings", function() {'
-            . "\n" . '	TYPO3.Form.Wizard.Settings = ' . json_encode($settings) . ';'
-            . "\n" . '	return TYPO3.Form.Wizard.Settings;'
-            . "\n" . '});';
-        return $settingsCommand;
-    }
-
-    /**
-     * Load the wizards css
-     */
-    protected function resultAddWizardCss()
-    {
-        $this->resultArray['stylesheetFiles'][] = 'EXT:form/Resources/Public/Css/form.css';
-    }
-
-    /**
-     * @return array
-     */
-    public function render()
-    {
-        $this->initializeResultArray();
-
-        /** @var \TYPO3\CMS\Core\Authentication\BackendUserAuthentication $beUser */
-        $beUser = $GLOBALS['BE_USER'];
-        /** @var string $showWizardByDefault */
-        $showWizardByDefault = $beUser->getTSConfigVal('setup.default.tx_form.showWizardByDefault');
-        if ((int)$showWizardByDefault == 0) {
-            $content = '';
-            $record = $this->getRepository()->getRecord($this->getCurrentUid(), 'tt_content');
-            if ($record) {
-                $content = $record->getBodytext();
-            }
-
-            $id = StringUtility::getUniqueId('formengine-textarea-');
-            $this->resultArray['html'] = '<textarea id="formengine-textarea-' . $id . '"'
-            . ' class="form-control t3js-formengine-textarea formengine-textarea" wrap="off"'
-            . ' onchange="TBE_EDITOR.fieldChanged(\'tt_content\',\'' . $this->getCurrentUid() . '\',\'bodytext\',\'data[tt_content][' . $this->getCurrentUid() . '][bodytext]\');"'
-            . ' rows="15" style="" name="data[tt_content][' . $this->getCurrentUid() . '][bodytext]">' . $content . '</textarea>';
-            return $this->resultArray;
-        }
-
-        $this->resultAddWizardCss();
-        $this->resultArray['additionalInlineLanguageLabelFiles'] += $this->getLocalization();
-        $settings = $this->getPlainPageWizardModTsConfigSettingsProperties();
-        $settingsCommand = $this->resultAddWizardSettingsJson($settings);
-        $this->resultArray['requireJsModules'][] = [
-            'TYPO3/CMS/Form/Wizard' => "function(){\n"
-                //. "\t" . 'console.log(this, arguments);' . "\n"
-                . "\t" . $settingsCommand . "\n"
-                . '}'
-        ];
-        $attributes = [];
-        $attributes['id'] = StringUtility::getUniqueId('formengine-form-wizard-');
-        /**
-         * @see TYPO3.CMS/src/typo3/sysext/backend/Classes/Form/Element/AbstractFormElement.php:267 for wizard type=popup
-         */
-        $parameterArray = $this->data['parameterArray'];
-        $attributes['name'] = $parameterArray['itemFormElName'];
-
-        $attributeString = '';
-        foreach ($attributes as $attributeName => $attributeValue) {
-            $attributeString .= ' ' . $attributeName . '="' . htmlspecialchars($attributeValue) . '"';
-        }
-
-        $input = '<input ' . $attributeString . ' type="hidden" />' . "\n";
-        $content = $input . '<div id="form-wizard-element"></div>';
-        $this->resultArray['html'] = '<div id="form-wizard-element-container" rel="' . $attributes['id'] . '">'
-            . "\n" . $content
-            . "\n" . '</div>';
-        return $this->resultArray;
-    }
-
-    /**
-     * @return TypoScriptService
-     */
-    protected function getTypoScriptService()
-    {
-        return GeneralUtility::makeInstance(TypoScriptService::class);
-    }
-}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/AggregateSelectOptionsViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/AggregateSelectOptionsViewHelper.php
deleted file mode 100644
index 92b78094d7f9d51d90cc2080b5a1244f5b906a8b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/ViewHelpers/AggregateSelectOptionsViewHelper.php
+++ /dev/null
@@ -1,116 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\ViewHelpers;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
-use TYPO3\CMS\Form\Domain\Model\Element;
-
-/**
- * Aggregator for the select options
- */
-class AggregateSelectOptionsViewHelper extends AbstractViewHelper
-{
-    /**
-     * @var array
-     */
-    protected $options = [];
-
-    /**
-     * @var array
-     */
-    protected $selectedValues = [];
-
-    /**
-     * Initializes the arguments
-     */
-    public function initializeArguments()
-    {
-        parent::initializeArguments();
-        $this->registerArgument('model', Element::class, '', true);
-        $this->registerArgument('returnSelectedValues', 'bool', '', false, false);
-    }
-
-    /**
-     * @return array
-     */
-    public function render()
-    {
-        /** @var Element $model */
-        $model = $this->arguments['model'];
-        /** @var Element $element */
-        foreach ($model->getChildElements() as $element) {
-            $this->createElement($element);
-        }
-
-        return $this->arguments['returnSelectedValues'] ? $this->selectedValues : $this->options;
-    }
-
-    /**
-     * @param Element $model
-     * @param array $optGroupData
-     * @return void
-     */
-    protected function createElement(Element $model, array $optGroupData = [])
-    {
-        $this->checkElementForOptgroup($model, $optGroupData);
-    }
-
-    /**
-     * @param Element $model
-     * @param array $optGroupData
-     * @return void
-     */
-    protected function checkElementForOptgroup(Element $model, array $optGroupData = [])
-    {
-        if ($model->getElementType() === 'OPTGROUP') {
-            $optGroupData = [
-                'label' => $model->getAdditionalArgument('label'),
-                'disabled' => $model->getAdditionalArgument('disabled'),
-            ];
-            $this->getChildElements($model, $optGroupData);
-        } else {
-            $optionData = [
-                'value' => $model->getAdditionalArgument('value') ?: $model->getElementCounter(),
-                'label' => $model->getAdditionalArgument('text'),
-                'selected' => $model->getAdditionalArgument('selected'),
-            ];
-
-            if (!empty($optionData['selected'])) {
-                $this->selectedValues[] = $optionData['value'];
-            }
-
-            if (count($optGroupData)) {
-                $optGroupLabel = $optGroupData['label'];
-                $this->options[$optGroupLabel]['disabled'] = $optGroupData['disabled'];
-                $this->options[$optGroupLabel]['options'][] = $optionData;
-            } else {
-                $this->options[] = $optionData;
-            }
-        }
-    }
-
-    /**
-     * @param Element $model
-     * @param array $optGroupData
-     * @return void
-     */
-    protected function getChildElements(Element $model, array $optGroupData = [])
-    {
-        /** @var Element $element */
-        foreach ($model->getChildElements() as $element) {
-            $this->createElement($element, $optGroupData);
-        }
-    }
-}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/Be/PageRendererViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/Be/PageRendererViewHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..0c32752b168ed7f4db40829a06ad5d643957f53b
--- /dev/null
+++ b/typo3/sysext/form/Classes/ViewHelpers/Be/PageRendererViewHelper.php
@@ -0,0 +1,56 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\ViewHelpers\Be;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Fluid\ViewHelpers\Be\PageRendererViewHelper as FluidPageRendererViewHelper;
+
+/**
+ * Extends the FluidPageRendererViewHelper
+ * Add the additional argument 'addInlineSettings' to add settings to
+ * the TYPO3 javascript inline setting
+ *
+ * Scope: backend
+ * @internal
+ */
+class PageRendererViewHelper extends FluidPageRendererViewHelper
+{
+
+    /**
+     * Initialize arguments.
+     *
+     * @return void
+     * @internal
+     */
+    public function initializeArguments()
+    {
+        parent::initializeArguments();
+        $this->registerArgument('addInlineSettings', 'array', 'Adds Javascript Inline Setting');
+    }
+
+    /**
+     * @return void
+     * @internal
+     */
+    public function render()
+    {
+        $addInlineSettings = $this->arguments['addInlineSettings'];
+        if (is_array($addInlineSettings) && count($addInlineSettings) > 0) {
+            $this->pageRenderer->addInlineSettingArray(null, $addInlineSettings);
+        }
+
+        parent::render();
+    }
+}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/Be/RenderContentElementPreviewViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/Be/RenderContentElementPreviewViewHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..a03f342b8679215eddf2df0de7a817fb8509d95a
--- /dev/null
+++ b/typo3/sysext/form/Classes/ViewHelpers/Be/RenderContentElementPreviewViewHelper.php
@@ -0,0 +1,73 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\ViewHelpers\Be;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Backend\View\PageLayoutView;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
+
+/**
+ * Used by the form editor.
+ * Render a content element preview like the page module
+ *
+ * Scope: backend
+ * @internal
+ */
+class RenderContentElementPreviewViewHelper extends AbstractViewHelper
+{
+    use CompileWithRenderStatic;
+
+    /**
+     * As this ViewHelper renders HTML, the output must not be escaped.
+     *
+     * @var bool
+     */
+    protected $escapeOutput = false;
+
+    /**
+     * Initialize arguments.
+     *
+     * @return void
+     * @internal
+     */
+    public function initializeArguments()
+    {
+        parent::initializeArguments();
+        $this->registerArgument('contentElementUid', 'int', 'The uid of a content element');
+    }
+
+    /**
+     * @param array $arguments
+     * @param callable|\Closure $renderChildrenClosure
+     * @param RenderingContextInterface $renderingContext
+     * @return string
+     * @internal
+     */
+    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
+    {
+        $content = '';
+        $contentElementUid = $arguments['contentElementUid'];
+        $contentRecord = BackendUtility::getRecord('tt_content', $contentElementUid);
+        if (!empty($contentRecord)) {
+            $pageLayoutView = GeneralUtility::makeInstance(PageLayoutView::class);
+            $content = $pageLayoutView->tt_content_drawItem($contentRecord);
+        }
+        return $content;
+    }
+}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/Form/CheckboxViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/Form/CheckboxViewHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..400fcbacc5c9234fecd348a95ad857a4ac8ce888
--- /dev/null
+++ b/typo3/sysext/form/Classes/ViewHelpers/Form/CheckboxViewHelper.php
@@ -0,0 +1,41 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\ViewHelpers\Form;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Fluid\ViewHelpers\Form\CheckboxViewHelper as FluidCheckboxViewHelper;
+
+/**
+ * Fix a bug within the fluid checkbox viewhelper.
+ * It is not possible to pass a bool value for the 'multiple' option
+ *
+ * Scope: frontend
+ * @api
+ */
+class CheckboxViewHelper extends FluidCheckboxViewHelper
+{
+
+    /**
+     * Renders the checkbox.
+     *
+     * @return string
+     * @api
+     */
+    public function render()
+    {
+        $this->arguments['multiple'] = (bool)$this->arguments['multiple'];
+        return parent::render();
+    }
+}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/Form/DatePickerViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/Form/DatePickerViewHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..b586e4b26d83e775325a11d918c6496b0de3b903
--- /dev/null
+++ b/typo3/sysext/form/Classes/ViewHelpers/Form/DatePickerViewHelper.php
@@ -0,0 +1,161 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\ViewHelpers\Form;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Property\PropertyMapper;
+use TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFieldViewHelper;
+
+/**
+ * Display a jQuery date picker.
+ *
+ * Note: Requires jQuery UI to be included on the page.
+ *
+ * Scope: frontend
+ * @api
+ */
+class DatePickerViewHelper extends AbstractFormFieldViewHelper
+{
+
+    /**
+     * @var string
+     */
+    protected $tagName = 'input';
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Property\PropertyMapper
+     */
+    protected $propertyMapper;
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Property\PropertyMapper $propertyMapper
+     * @return void
+     * @internal
+     */
+    public function injectPropertyMapper(\TYPO3\CMS\Extbase\Property\PropertyMapper $propertyMapper)
+    {
+        $this->propertyMapper = $propertyMapper;
+    }
+
+    /**
+     * Initialize the arguments.
+     *
+     * @return void
+     * @api
+     */
+    public function initializeArguments()
+    {
+        parent::initializeArguments();
+        $this->registerTagAttribute('size', 'int', 'The size of the input field');
+        $this->registerTagAttribute('placeholder', 'string', 'Specifies a short hint that describes the expected value of an input element');
+        $this->registerArgument('errorClass', 'string', 'CSS class to set if there are errors for this view helper', false, 'f3-form-error');
+        $this->registerArgument('initialDate', 'string', 'Initial date (@see http://www.php.net/manual/en/datetime.formats.php for supported formats)');
+        $this->registerArgument('enableDatePicker', 'bool', 'Enable the Datepicker', false, true);
+        $this->registerArgument('dateFormat', 'string', 'The date format', false, 'Y-m-d');
+        $this->registerUniversalTagAttributes();
+    }
+
+    /**
+     * Renders the text field, hidden field and required javascript
+     *
+     * @return string
+     * @api
+     */
+    public function render()
+    {
+        $enableDatePicker = $this->arguments['enableDatePicker'];
+        $dateFormat = $this->arguments['dateFormat'];
+
+        $name = $this->getName();
+        $this->registerFieldNameForFormTokenGeneration($name);
+
+        $this->tag->addAttribute('type', 'date');
+        $this->tag->addAttribute('name', $name . '[date]');
+        if ($enableDatePicker) {
+            $this->tag->addAttribute('readonly', true);
+        }
+        $date = $this->getSelectedDate();
+        if ($date !== null) {
+            $this->tag->addAttribute('value', $date->format($dateFormat));
+        }
+
+        if ($this->hasArgument('id')) {
+            $id = $this->arguments['id'];
+        } else {
+            $id = 'field' . md5(uniqid());
+            $this->tag->addAttribute('id', $id);
+        }
+        $this->setErrorClassAttribute();
+        $content = '';
+        $content .= $this->tag->render();
+        $content .= '<input type="hidden" name="' . $name . '[dateFormat]" value="' . htmlspecialchars($dateFormat) . '" />';
+
+        if ($enableDatePicker) {
+            $datePickerDateFormat = $this->convertDateFormatToDatePickerFormat($dateFormat);
+            $this->templateVariableContainer->add('datePickerDateFormat', $datePickerDateFormat);
+            $content .= $this->renderChildren();
+            $this->templateVariableContainer->remove('datePickerDateFormat');
+        }
+        return $content;
+    }
+
+    /**
+     * @return null|\DateTime
+     */
+    protected function getSelectedDate()
+    {
+        $fluidFormRenderer = $this->viewHelperVariableContainer->getView();
+        $formRuntime = $fluidFormRenderer->getFormRuntime();
+        $formState = $formRuntime->getFormState();
+
+        $date = $formRuntime[$this->arguments['property']];
+        if ($date instanceof \DateTime) {
+            return $date;
+        }
+        if ($date !== null) {
+            $date = $this->propertyMapper->convert($date, 'DateTime');
+            if (!$date instanceof \DateTime) {
+                return null;
+            }
+            return $date;
+        }
+        if ($this->hasArgument('initialDate')) {
+            return new \DateTime($this->arguments['initialDate']);
+        }
+    }
+
+    /**
+     * @param string $dateFormat
+     * @return string
+     */
+    protected function convertDateFormatToDatePickerFormat(string $dateFormat): string
+    {
+        $replacements = [
+            'd' => 'dd',
+            'D' => 'D',
+            'j' => 'o',
+            'l' => 'DD',
+
+            'F' => 'MM',
+            'm' => 'mm',
+            'M' => 'M',
+            'n' => 'm',
+
+            'Y' => 'yy',
+            'y' => 'y'
+        ];
+        return strtr($dateFormat, $replacements);
+    }
+}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/Form/TimePickerViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/Form/TimePickerViewHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..9b3d0fc21cda46c47d2ce8b759691435a72bc134
--- /dev/null
+++ b/typo3/sysext/form/Classes/ViewHelpers/Form/TimePickerViewHelper.php
@@ -0,0 +1,152 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\ViewHelpers\Form;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Property\PropertyMapper;
+use TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFieldViewHelper;
+
+/**
+ * Displays two select-boxes for hour and minute selection.
+ *
+ * Scope: frontend
+ * @api
+ */
+class TimePickerViewHelper extends AbstractFormFieldViewHelper
+{
+
+    /**
+     * @var string
+     */
+    protected $tagName = 'select';
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Property\PropertyMapper
+     */
+    protected $propertyMapper;
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Property\PropertyMapper $propertyMapper
+     * @return void
+     * @internal
+     */
+    public function injectPropertyMapper(\TYPO3\CMS\Extbase\Property\PropertyMapper $propertyMapper)
+    {
+        $this->propertyMapper = $propertyMapper;
+    }
+
+    /**
+     * Initialize the arguments.
+     *
+     * @return void
+     * @internal
+     */
+    public function initializeArguments()
+    {
+        parent::initializeArguments();
+        $this->registerTagAttribute('size', 'int', 'The size of the select field');
+        $this->registerTagAttribute('placeholder', 'string', 'Specifies a short hint that describes the expected value of an input element');
+        $this->registerTagAttribute('disabled', 'string', 'Specifies that the select element should be disabled when the page loads');
+        $this->registerArgument('errorClass', 'string', 'CSS class to set if there are errors for this view helper', false, 'f3-form-error');
+        $this->registerArgument('initialDate', 'string', 'Initial time (@see http://www.php.net/manual/en/datetime.formats.php for supported formats)');
+        $this->registerUniversalTagAttributes();
+    }
+
+    /**
+     * Renders the select fields for hour & minute
+     *
+     * @return string
+     * @api
+     */
+    public function render()
+    {
+        $name = $this->getName();
+        $this->registerFieldNameForFormTokenGeneration($name);
+
+        $this->tag->addAttribute('name', $name . '[hour]');
+        $date = $this->getSelectedDate();
+        $this->setErrorClassAttribute();
+
+        $content = '';
+        $content .= $this->buildHourSelector($date);
+        $content .= $this->buildMinuteSelector($date);
+        return $content;
+    }
+
+    /**
+     * @return \DateTime
+     */
+    protected function getSelectedDate(): \DateTime
+    {
+        $fluidFormRenderer = $this->viewHelperVariableContainer->getView();
+        $formRuntime = $fluidFormRenderer->getFormRuntime();
+
+        $date = $formRuntime[$this->arguments['property']];
+        if ($date instanceof \DateTime) {
+            return $date;
+        }
+        if ($date !== null) {
+            $date = $this->propertyMapper->convert($date, 'DateTime');
+            if (!$date instanceof \DateTime) {
+                return null;
+            }
+            return $date;
+        }
+        if ($this->hasArgument('initialDate')) {
+            return new \DateTime($this->arguments['initialDate']);
+        }
+    }
+
+    /**
+     * @param \DateTime $date
+     * @return string
+     */
+    protected function buildHourSelector(\DateTime $date = null): string
+    {
+        $value = $date !== null ? $date->format('H') : null;
+        $hourSelector = clone $this->tag;
+        $hourSelector->addAttribute('name', sprintf('%s[hour]', $this->getName()));
+        $options = '';
+        foreach (range(0, 23) as $hour) {
+            $hour = str_pad($hour, 2, '0', STR_PAD_LEFT);
+            $selected = $hour === $value ? ' selected="selected"' : '';
+            $options .= '<option value="' . $hour . '"' . $selected . '>' . $hour . '</option>';
+        }
+        $hourSelector->setContent($options);
+        return $hourSelector->render();
+    }
+
+    /**
+     * @param \DateTime $date
+     * @return string
+     */
+    protected function buildMinuteSelector(\DateTime $date = null): string
+    {
+        $value = $date !== null ? $date->format('i') : null;
+        $minuteSelector = clone $this->tag;
+        if ($this->hasArgument('id')) {
+            $minuteSelector->addAttribute('id', $this->arguments['id'] . '-minute');
+        }
+        $minuteSelector->addAttribute('name', sprintf('%s[minute]', $this->getName()));
+        $options = '';
+        foreach (range(0, 59) as $minute) {
+            $minute = str_pad($minute, 2, '0', STR_PAD_LEFT);
+            $selected = $minute === $value ? ' selected="selected"' : '';
+            $options .= '<option value="' . $minute . '"' . $selected . '>' . $minute . '</option>';
+        }
+        $minuteSelector->setContent($options);
+        return $minuteSelector->render();
+    }
+}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/Form/UploadedResourceViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/Form/UploadedResourceViewHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..988c3114d13173b6158cb7a1f6ce2b6dc3413d51
--- /dev/null
+++ b/typo3/sysext/form/Classes/ViewHelpers/Form/UploadedResourceViewHelper.php
@@ -0,0 +1,133 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\ViewHelpers\Form;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Domain\Model\FileReference;
+use TYPO3\CMS\Extbase\Property\PropertyMapper;
+use TYPO3\CMS\Extbase\Security\Cryptography\HashService;
+use TYPO3\CMS\Fluid\ViewHelpers\Form\UploadViewHelper;
+
+/**
+ * This ViewHelper makes the specified Image object available for its
+ * childNodes.
+ * In case the form is redisplayed because of validation errors, a previously
+ * uploaded image will be correctly used.
+ *
+ * Scope: frontend
+ * @api
+ */
+class UploadedResourceViewHelper extends UploadViewHelper
+{
+
+    /**
+     * @var HashService
+     */
+    protected $hashService;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Property\PropertyMapper
+     */
+    protected $propertyMapper;
+
+    /**
+     * @param HashService $hashService
+     * @return void
+     * @internal
+     */
+    public function injectHashService(\TYPO3\CMS\Extbase\Security\Cryptography\HashService $hashService)
+    {
+        $this->hashService = $hashService;
+    }
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Property\PropertyMapper $propertyMapper
+     * @return void
+     * @internal
+     */
+    public function injectPropertyMapper(\TYPO3\CMS\Extbase\Property\PropertyMapper $propertyMapper)
+    {
+        $this->propertyMapper = $propertyMapper;
+    }
+
+    /**
+     * Initialize the arguments.
+     *
+     * @return void
+     * @internal
+     */
+    public function initializeArguments()
+    {
+        parent::initializeArguments();
+        $this->registerArgument('as', 'string', '');
+        $this->registerArgument('accept', 'array', 'Values for the accept attribute', false, []);
+    }
+
+    /**
+     * @return string
+     * @api
+     */
+    public function render()
+    {
+        $output = '';
+
+        $as = $this->arguments['as'];
+        $accept = $this->arguments['accept'];
+        $resource = $this->getUploadedResource();
+
+        if (!empty($accept)) {
+            $this->tag->addAttribute('accept', implode(',', $accept));
+        }
+
+        if ($resource !== null) {
+            $resourcePointerIdAttribute = '';
+            if ($this->hasArgument('id')) {
+                $resourcePointerIdAttribute = ' id="' . htmlspecialchars($this->arguments['id']) . '-file-reference"';
+            }
+            $resourcePointerValue = $resource->getUid();
+            if ($resourcePointerValue === null) {
+                // Newly created file reference which is not persisted yet.
+                // Use the file UID instead, but prefix it with "file:" to communicate this to the type converter
+                $resourcePointerValue = 'file:' . $resource->getOriginalResource()->getOriginalFile()->getUid();
+            }
+            $output .= '<input type="hidden" name="' . $this->getName() . '[submittedFile][resourcePointer]" value="' . htmlspecialchars($this->hashService->appendHmac((string)$resourcePointerValue)) . '"' . $resourcePointerIdAttribute . ' />';
+
+            $this->templateVariableContainer->add($as, $resource);
+            $output .= $this->renderChildren();
+            $this->templateVariableContainer->remove($as);
+        }
+
+        $output .= parent::render();
+        return $output;
+    }
+
+    /**
+     * Return a previously uploaded resource.
+     * Return NULL if errors occurred during property mapping for this property.
+     *
+     * @return null|FileReference
+     */
+    protected function getUploadedResource()
+    {
+        if ($this->getMappingResultsForProperty()->hasErrors()) {
+            return null;
+        }
+        $resource = $this->getValueAttribute();
+        if ($resource instanceof FileReference) {
+            return $resource;
+        }
+        return $this->propertyMapper->convert($resource, FileReference::class);
+    }
+}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/FormViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/FormViewHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..d6e2e18709be8dc41a47b66c1bf4425c34290f36
--- /dev/null
+++ b/typo3/sysext/form/Classes/ViewHelpers/FormViewHelper.php
@@ -0,0 +1,62 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\ViewHelpers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Extbase\Mvc\Web\Request;
+use TYPO3\CMS\Extbase\Security\Cryptography\HashService;
+use TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper as FluidFormViewHelper;
+use TYPO3Fluid\Fluid\Core\ViewHelper\TagBuilder;
+
+/**
+ * Custom form ViewHelper that renders the form state instead of referrer fields
+ *
+ * Scope: frontend
+ * @api
+ */
+class FormViewHelper extends FluidFormViewHelper
+{
+
+    /**
+     * Renders hidden form fields for referrer information about
+     * the current request.
+     *
+     * @return string Hidden fields with referrer information
+     */
+    protected function renderHiddenReferrerFields()
+    {
+        $tagBuilder = $this->objectManager->get(TagBuilder::class, 'input');
+        $tagBuilder->addAttribute('type', 'hidden');
+        $stateName = $this->prefixFieldName($this->arguments['object']->getFormDefinition()->getIdentifier()) . '[__state]';
+        $tagBuilder->addAttribute('name', $stateName);
+
+        $serializedFormState = base64_encode(serialize($this->arguments['object']->getFormState()));
+        $tagBuilder->addAttribute('value', $this->hashService->appendHmac($serializedFormState));
+        return $tagBuilder->render();
+    }
+
+    /**
+     * We do NOT return NULL as in this case, the Form ViewHelpers do not enter $objectAccessorMode.
+     * However, we return the form identifier.
+     *
+     * @return string
+     */
+    protected function getFormObjectName()
+    {
+        $fluidFormRenderer = $this->viewHelperVariableContainer->getView();
+        $formRuntime = $fluidFormRenderer->getFormRuntime();
+        return $formRuntime->getFormDefinition()->getIdentifier();
+    }
+}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/PlainMailViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/PlainMailViewHelper.php
deleted file mode 100644
index 50263817e0fbdaabdf2efd1023cca1dabbed17c0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/ViewHelpers/PlainMailViewHelper.php
+++ /dev/null
@@ -1,132 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\ViewHelpers;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
-use TYPO3\CMS\Form\Domain\Model\Element;
-
-/**
- * A viewhelper for the plain mail view
- */
-class PlainMailViewHelper extends AbstractViewHelper
-{
-    /**
-     * Initializes the arguments
-     */
-    public function initializeArguments()
-    {
-        parent::initializeArguments();
-        $this->registerArgument('labelContent', 'mixed', '');
-        $this->registerArgument('content', 'mixed', '');
-        $this->registerArgument('newLineAfterLabel', 'bool', '', false, false);
-        $this->registerArgument('indent', 'int', '', false, 0);
-    }
-
-    /**
-     * Render the plain mail view
-     *
-     * @return string
-     */
-    public function render()
-    {
-        $templateVariableContainer = $this->renderingContext->getViewHelperVariableContainer();
-        if (!$templateVariableContainer->exists(__CLASS__, 'spaces')) {
-            $templateVariableContainer->add(__CLASS__, 'spaces', 0);
-        }
-
-        $spaces = $templateVariableContainer->get(__CLASS__, 'spaces');
-        $output = '';
-        if ($this->arguments['labelContent']) {
-            if ($this->arguments['labelContent'] instanceof Element) {
-                $output = $this->getLabel($this->arguments['labelContent']);
-            } else {
-                $output = $this->arguments['labelContent'];
-            }
-            if ($this->arguments['newLineAfterLabel']) {
-                if ($output !== '') {
-                    $output = str_repeat(chr(32), $spaces) . $output . LF;
-                }
-                $this->setIndent($this->arguments['indent']);
-            }
-        }
-
-        if ($this->arguments['content']) {
-            if (!$this->arguments['newLineAfterLabel']) {
-                $this->setIndent($this->arguments['indent']);
-            }
-            if ($this->arguments['labelContent'] && !$this->arguments['newLineAfterLabel']) {
-                $output = $output . ': ' . $this->getValue($this->arguments['content']);
-            } elseif ($this->arguments['labelContent'] && $this->arguments['newLineAfterLabel']) {
-                $output = $output
-                    . str_repeat(chr(32), ($spaces + 4))
-                    . str_replace(LF, LF . str_repeat(chr(32), ($spaces + 4)), $this->getValue($this->arguments['content']));
-            } else {
-                $output = $this->getValue($this->arguments['content']);
-            }
-        }
-
-        if ($this->arguments['labelContent'] || $this->arguments['content']) {
-            if ($output !== '' && !$this->arguments['newLineAfterLabel']) {
-                $output = str_repeat(chr(32), $spaces) . $output;
-            }
-        } else {
-            $this->setIndent($this->arguments['indent']);
-        }
-
-        return $output;
-    }
-
-    /**
-     * Get the label
-     * @param Element $model
-     * @return string
-     */
-    protected function getLabel(Element $model)
-    {
-        $label = '';
-        if ($model->getAdditionalArgument('legend')) {
-            $label = $model->getAdditionalArgument('legend');
-        } elseif ($model->getAdditionalArgument('label')) {
-            $label = $model->getAdditionalArgument('label');
-        }
-        return $label;
-    }
-
-    /**
-     * Get the label
-     *
-     * @param string $content
-     * @return string
-     */
-    protected function getValue($content)
-    {
-        return $content instanceof Element ? $content->getAdditionalArgument('value') : $content;
-    }
-
-    /**
-     * Set the current indent level
-     *
-     * @param int $indent
-     * @return void
-     */
-    public function setIndent($indent = 0)
-    {
-        $templateVariableContainer = $this->renderingContext->getViewHelperVariableContainer();
-        $spaces = $templateVariableContainer->get(__CLASS__, 'spaces');
-        $spaces += (int)$indent;
-        $templateVariableContainer->addOrUpdate(__CLASS__, 'indent', $indent);
-        $templateVariableContainer->addOrUpdate(__CLASS__, 'spaces', $spaces);
-    }
-}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/PlainTextMailViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/PlainTextMailViewHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..0b8e0f4efd1764fabc449d82269a3ef1d0c9f26d
--- /dev/null
+++ b/typo3/sysext/form/Classes/ViewHelpers/PlainTextMailViewHelper.php
@@ -0,0 +1,79 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\ViewHelpers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
+
+/**
+ * A viewhelper for the plain mail view
+ *
+ * Scope: frontend
+ * @api
+ */
+class PlainTextMailViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper
+{
+    use CompileWithRenderStatic;
+
+    /**
+     * Initialize the arguments.
+     *
+     * @return void
+     * @internal
+     */
+    public function initializeArguments()
+    {
+        parent::initializeArguments();
+        $this->registerArgument('formValue', 'array', 'The values from a form element', true);
+        $this->registerArgument('formRuntime', FormRuntime::class, 'A FormRuntime instance', true);
+    }
+
+    /**
+     * @param array $arguments
+     * @param callable|\Closure $renderChildrenClosure
+     * @param RenderingContextInterface $renderingContext
+     * @return string
+     * @api
+     */
+    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
+    {
+        $formValue = $arguments['formValue'];
+        $formRuntime = $arguments['formRuntime'];
+
+        $label = $formValue['element']->getLabel();
+        $label = TranslateElementPropertyViewHelper::renderStatic(
+            ['element' => $formValue['element'], 'property' => 'label', 'formRuntime' => $formRuntime],
+            $renderChildrenClosure,
+            $renderingContext
+        );
+        $processedValue = (!empty($formValue['processedValue'])) ? $formValue['processedValue'] : '-';
+        $isMultiValue = $formValue['isMultiValue'];
+
+        $label .= ': ';
+        if ($isMultiValue) {
+            $output = $label . array_shift($processedValue) . LF;
+            $indent = str_repeat(chr(32), (strlen($label)));
+            foreach ($processedValue as $multiValue) {
+                $output .= $indent . $multiValue;
+            }
+        } else {
+            $output = $label . $processedValue;
+        }
+
+        return $output . LF . LF;
+    }
+}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/RenderAllFormValuesViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/RenderAllFormValuesViewHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..31fe05006ea75c002f9f90f274367b18b81fc2ac
--- /dev/null
+++ b/typo3/sysext/form/Classes/ViewHelpers/RenderAllFormValuesViewHelper.php
@@ -0,0 +1,190 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\ViewHelpers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Resource\File;
+use TYPO3\CMS\Extbase\Domain\Model\FileReference;
+use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+use TYPO3\CMS\Form\Domain\Model\FormElements\FormElementInterface;
+use TYPO3\CMS\Form\Domain\Model\Renderable\CompositeRenderableInterface;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface;
+use TYPO3\CMS\Form\Domain\Renderer\RendererInterface;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+
+/**
+ * Renders the values of a form
+ *
+ * Scope: frontend
+ * @api
+ */
+class RenderAllFormValuesViewHelper extends AbstractViewHelper
+{
+
+    /**
+     * @var bool
+     */
+    protected $escapeOutput = false;
+
+    /**
+     * Initialize the arguments.
+     *
+     * @return void
+     * @internal
+     */
+    public function initializeArguments()
+    {
+        parent::initializeArguments();
+        $this->registerArgument('renderable', RootRenderableInterface::class, 'A RootRenderableInterface instance', true);
+        $this->registerArgument('as', 'string', 'The name within the template', false, 'formValue');
+        $this->registerArgument('formRuntime', FormRuntime::class, 'A FormRuntime instance', false, null);
+    }
+
+    /**
+     * @return string the rendered form values
+     * @api
+     */
+    public function render()
+    {
+        $renderable = $this->arguments['renderable'];
+        $as = $this->arguments['as'];
+        $formRuntime = $this->arguments['formRuntime'];
+
+        if ($renderable instanceof CompositeRenderableInterface) {
+            $elements = $renderable->getRenderablesRecursively();
+        } else {
+            $elements = [$renderable];
+        }
+
+        if ($formRuntime === null) {
+            /** @var RendererInterface $fluidFormRenderer */
+            $fluidFormRenderer = $this->viewHelperVariableContainer->getView();
+            $formRuntime = $fluidFormRenderer->getFormRuntime();
+        }
+
+        $output = '';
+        foreach ($elements as $element) {
+            if (!$element instanceof FormElementInterface || $element->getType() === 'Honeypot') {
+                continue;
+            }
+            $value = $formRuntime[$element->getIdentifier()];
+
+            $formValue = [
+                'element' => $element,
+                'value' => $value,
+                'processedValue' => $this->processElementValue($element, $value, $formRuntime),
+                'isMultiValue' => is_array($value) || $value instanceof \Iterator
+            ];
+            $this->templateVariableContainer->add($as, $formValue);
+            $output .= $this->renderChildren();
+            $this->templateVariableContainer->remove($as);
+        }
+        return $output;
+    }
+
+    /**
+     * Converts the given value to a simple type (string or array) considering the underlying FormElement definition
+     *
+     * @param FormElementInterface $element
+     * @param mixed $value
+     * @param FormRuntime $formRuntime
+     * @return mixed
+     */
+    protected function processElementValue(FormElementInterface $element, $value, FormRuntime $formRuntime)
+    {
+        $properties = $element->getProperties();
+        if (isset($properties['options']) && is_array($properties['options'])) {
+            $properties['options'] = TranslateElementPropertyViewHelper::renderStatic(
+                ['element' => $element, 'property' => 'options', 'formRuntime' => $formRuntime],
+                $this->buildRenderChildrenClosure(),
+                $this->renderingContext
+            );
+            if (is_array($value)) {
+                return $this->mapValuesToOptions($value, $properties['options']);
+            } else {
+                return $this->mapValueToOption($value, $properties['options']);
+            }
+        }
+        if (is_object($value)) {
+            return $this->processObject($element, $value);
+        }
+        return $value;
+    }
+
+    /**
+     * Replaces the given values (=keys) with the corresponding elements in $options
+     * @see mapValueToOption()
+     *
+     * @param array $value
+     * @param array $options
+     * @return array
+     */
+    protected function mapValuesToOptions(array $value, array $options): array
+    {
+        $result = [];
+        foreach ($value as $key) {
+            $result[] = $this->mapValueToOption($key, $options);
+        }
+        return $result;
+    }
+
+    /**
+     * Replaces the given value (=key) with the corresponding element in $options
+     * If the key does not exist in $options, it is returned without modification
+     *
+     * @param mixed $value
+     * @param array $options
+     * @return mixed
+     */
+    protected function mapValueToOption($value, array $options)
+    {
+        return isset($options[$value]) ? $options[$value] : $value;
+    }
+
+    /**
+     * Converts the given $object to a string representation considering the $element FormElement definition
+     *
+     * @param FormElementInterface $element
+     * @param object $object
+     * @return string
+     */
+    protected function processObject(FormElementInterface $element, $object): string
+    {
+        $properties = $element->getProperties();
+        if ($object instanceof \DateTime) {
+            if (isset($properties['dateFormat'])) {
+                $dateFormat = $properties['dateFormat'];
+                if (isset($properties['displayTimeSelector']) && $properties['displayTimeSelector'] === true) {
+                    $dateFormat .= ' H:i';
+                }
+            } else {
+                $dateFormat = \DateTime::W3C;
+            }
+            return $object->format($dateFormat);
+        }
+
+        if ($object instanceof File || $object instanceof FileReference) {
+            if ($object instanceof FileReference) {
+                $object = $object->getOriginalResource();
+            }
+            return $object->getName();
+        }
+
+        if (method_exists($object, '__toString')) {
+            return (string)$object;
+        }
+        return 'Object [' . get_class($object) . ']';
+    }
+}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/RenderRenderableViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/RenderRenderableViewHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..b454752c448994a77ad079a7710f5c4afbe05646
--- /dev/null
+++ b/typo3/sysext/form/Classes/ViewHelpers/RenderRenderableViewHelper.php
@@ -0,0 +1,66 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\ViewHelpers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface;
+use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
+
+/**
+ * Render a renderable.
+ *
+ * Set the renderable into the \TYPO3\CMS\Form\Mvc\View\FormView
+ * and return the rendered content.
+ *
+ * Scope: frontend
+ * @api
+ */
+class RenderRenderableViewHelper extends AbstractViewHelper
+{
+    use CompileWithRenderStatic;
+
+    /**
+     * @var bool
+     */
+    protected $escapeOutput = false;
+
+    /**
+     * Initialize the arguments.
+     *
+     * @return void
+     * @internal
+     */
+    public function initializeArguments()
+    {
+        parent::initializeArguments();
+        $this->registerArgument('renderable', RenderableInterface::class, 'A RenderableInterface instance', true);
+    }
+
+    /**
+     * @param array $arguments
+     * @param callable|\Closure $renderChildrenClosure
+     * @param RenderingContextInterface $renderingContext
+     * @return string
+     * @public
+     */
+    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
+    {
+        /** @var \TYPO3\CMS\Form\Mvc\View\FormView $view */
+        $view = $renderingContext->getViewHelperVariableContainer()->getView();
+        return $view->renderRenderable($arguments['renderable']);
+    }
+}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/RenderViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/RenderViewHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..7846237ad3195da59bd63650d92bbb20e98a7c34
--- /dev/null
+++ b/typo3/sysext/form/Classes/ViewHelpers/RenderViewHelper.php
@@ -0,0 +1,101 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\ViewHelpers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Utility\ArrayUtility;
+use TYPO3\CMS\Extbase\Mvc\Web\Response;
+use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+use TYPO3\CMS\Form\Domain\Factory\ArrayFormFactory;
+use TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface;
+use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
+
+/**
+ * Main Entry Point to render a Form into a Fluid Template
+ *
+ * Usage
+ * =====
+ *
+ * <pre>
+ * {namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+ * <formvh:render factoryClass="NameOfYourCustomFactoryClass" />
+ * </pre>
+ *
+ * The factory class must implement {@link TYPO3\CMS\Form\Domain\Factory\FormFactoryInterface}.
+ *
+ * Scope: frontend
+ * @api
+ */
+class RenderViewHelper extends AbstractViewHelper
+{
+    use CompileWithRenderStatic;
+
+    /**
+     * @var bool
+     */
+    protected $escapeOutput = false;
+
+    /**
+     * Initialize the arguments.
+     *
+     * @return void
+     * @internal
+     */
+    public function initializeArguments()
+    {
+        parent::initializeArguments();
+        $this->registerArgument('persistenceIdentifier', 'string', 'The persistence identifier for the form.', false, null);
+        $this->registerArgument('factoryClass', 'string', 'The fully qualified class name of the factory', false, ArrayFormFactory::class);
+        $this->registerArgument('prototypeName', 'string', 'Name of the prototype to use', false, null);
+        $this->registerArgument('overrideConfiguration', 'array', 'factory specific configuration', false, []);
+    }
+
+    /**
+     * @param array $arguments
+     * @param callable|\Closure $renderChildrenClosure
+     * @param RenderingContextInterface $renderingContext
+     * @return string
+     * @public
+     */
+    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
+    {
+        $persistenceIdentifier = $arguments['persistenceIdentifier'];
+        $factoryClass = $arguments['factoryClass'];
+        $prototypeName = $arguments['prototypeName'];
+        $overrideConfiguration = $arguments['overrideConfiguration'];
+
+        if (!empty($persistenceIdentifier)) {
+            $formPersistenceManager = $renderingContext->getObjectManager()->get(FormPersistenceManagerInterface::class);
+            $formConfiguration = $formPersistenceManager->load($persistenceIdentifier);
+            ArrayUtility::mergeRecursiveWithOverrule(
+                $formConfiguration,
+                $overrideConfiguration
+            );
+            $overrideConfiguration = $formConfiguration;
+            $overrideConfiguration['persistenceIdentifier'] = $persistenceIdentifier;
+        }
+
+        if (empty($prototypeName)) {
+            $prototypeName = isset($overrideConfiguration['prototypeName']) ? $overrideConfiguration['prototypeName'] : 'standard';
+        }
+
+        $factory = $renderingContext->getObjectManager()->get($factoryClass);
+        $formDefinition = $factory->build($overrideConfiguration, $prototypeName);
+        $response = $renderingContext->getObjectManager()->get(Response::class, $renderingContext->getControllerContext()->getResponse());
+        $form = $formDefinition->bind($renderingContext->getControllerContext()->getRequest(), $response);
+        return $form->render();
+    }
+}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/SelectViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/SelectViewHelper.php
deleted file mode 100644
index e1455c3177f4ea842b139b384bbb1eaf6eaefbc5..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Classes/ViewHelpers/SelectViewHelper.php
+++ /dev/null
@@ -1,139 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\ViewHelpers;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * The form wizard controller
- */
-class SelectViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\Form\SelectViewHelper
-{
-    /**
-     * Render the option tags.
-     *
-     * @return array an associative array of options, key will be the value of the option tag
-     */
-    protected function getOptions()
-    {
-        if (!is_array($this->arguments['options']) && !$this->arguments['options'] instanceof \Traversable) {
-            return [];
-        }
-        $options = [];
-        $optionsArgument = $this->arguments['options'];
-        foreach ($optionsArgument as $key => $value) {
-            if (is_string($key)) {
-                $options[$key]['disabled'] = $value['disabled'];
-                $options[$key]['isOptgroup'] = true;
-                $optGroupOptions = $value['options'];
-                foreach ($optGroupOptions as $optionKey => $optionValue) {
-                    $option = $this->getOption($optionKey, $optionValue);
-                    $options[$key]['options'][key($option)] = current($option);
-                }
-            } else {
-                $option = $this->getOption($key, $value);
-                $options[key($option)] = current($option);
-            }
-        }
-
-        if ($this->arguments['sortByOptionLabel']) {
-            asort($options, SORT_LOCALE_STRING);
-        }
-        return $options;
-    }
-
-    /**
-     * Build a option array.
-     *
-     * @param string $key
-     * @param string $value
-     * @return array an associative array of an option, key will be the value of the option tag
-     */
-    protected function getOption($key, $value)
-    {
-        $option = [];
-        if (is_object($value) || is_array($value)) {
-            if ($this->hasArgument('optionValueField')) {
-                $key = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($value, $this->arguments['optionValueField']);
-                if (is_object($key)) {
-                    if (method_exists($key, '__toString')) {
-                        $key = (string)$key;
-                    } else {
-                        throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('Identifying value for object of class "' . get_class($value) . '" was an object.', 1460975593);
-                    }
-                }
-            // @todo use $this->persistenceManager->isNewObject() once it is implemented
-            } elseif ($this->persistenceManager->getIdentifierByObject($value) !== null) {
-                $key = $this->persistenceManager->getIdentifierByObject($value);
-            } elseif (method_exists($value, '__toString')) {
-                $key = (string)$value;
-            } else {
-                throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('No identifying value for object of class "' . get_class($value) . '" found.', 1460975538);
-            }
-            if ($this->hasArgument('optionLabelField')) {
-                $value = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyPath($value, $this->arguments['optionLabelField']);
-                if (is_object($value)) {
-                    if (method_exists($value, '__toString')) {
-                        $value = (string)$value;
-                    } else {
-                        throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('Label value for object of class "' . get_class($value) . '" was an object without a __toString() method.', 1460975633);
-                    }
-                }
-            } elseif (method_exists($value, '__toString')) {
-                $value = (string)$value;
-            // @todo use $this->persistenceManager->isNewObject() once it is implemented
-            } elseif ($this->persistenceManager->getIdentifierByObject($value) !== null) {
-                $value = $this->persistenceManager->getIdentifierByObject($value);
-            }
-        }
-        $option[$key] = $value;
-        return $option;
-    }
-
-    /**
-     * Render the option tags.
-     *
-     * @param array $options the options for the form.
-     * @return string rendered tags.
-     */
-    protected function renderOptionTags($options)
-    {
-        $output = '';
-        if ($this->hasArgument('prependOptionLabel')) {
-            $value = $this->hasArgument('prependOptionValue') ? $this->arguments['prependOptionValue'] : '';
-            $label = $this->arguments['prependOptionLabel'];
-            $output .= $this->renderOptionTag($value, $label, false) . LF;
-        }
-        foreach ($options as $value => $label) {
-            if (
-                isset($label['isOptgroup'])
-                && $label['isOptgroup'] === true
-            ) {
-                $output .= '<optgroup label="' . htmlspecialchars($value) . '"';
-                if ($label['disabled'] !== null) {
-                    $output .= ' disabled="disabled"';
-                }
-                $output .= '>' . LF;
-                foreach ($label['options'] as $optionValue => $optionLabel) {
-                    $isSelected = $this->isSelected($optionValue);
-                    $output .= $this->renderOptionTag($optionValue, $optionLabel, $isSelected) . LF;
-                }
-                $output .= ' </optgroup>' . LF;
-            } else {
-                $isSelected = $this->isSelected($value);
-                $output .= $this->renderOptionTag($value, $label, $isSelected) . LF;
-            }
-        }
-        return $output;
-    }
-}
diff --git a/typo3/sysext/form/Classes/ViewHelpers/TranslateElementPropertyViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/TranslateElementPropertyViewHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..5abb18b4c59b3b2d3484922a527681043a698119
--- /dev/null
+++ b/typo3/sysext/form/Classes/ViewHelpers/TranslateElementPropertyViewHelper.php
@@ -0,0 +1,80 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\ViewHelpers;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
+use TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface;
+use TYPO3\CMS\Form\Domain\Renderer\RendererInterface;
+use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
+use TYPO3\CMS\Form\Service\TranslationService;
+use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
+
+/**
+ * Translate form element properites.
+ *
+ * Scope: frontend / backend
+ * @api
+ */
+class TranslateElementPropertyViewHelper extends AbstractViewHelper
+{
+    use CompileWithRenderStatic;
+
+    /**
+     * Initialize arguments.
+     *
+     * @return void
+     * @internal
+     */
+    public function initializeArguments()
+    {
+        parent::initializeArguments();
+        $this->registerArgument('element', RootRenderableInterface::class, 'Form Element to translate', true);
+        $this->registerArgument('property', 'string', 'Property to translate', false);
+        $this->registerArgument('renderingOptionProperty', 'string', 'Property to translate', false);
+        $this->registerArgument('formRuntime', FormRuntime::class, 'The form runtime', false);
+    }
+
+    /**
+     * Return array element by key.
+     *
+     * @param array $arguments
+     * @param \Closure $renderChildrenClosure
+     * @param RenderingContextInterface $renderingContext
+     * @return string
+     * @api
+     */
+    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
+    {
+        $element = $arguments['element'];
+        $formRuntime = $arguments['formRuntime'];
+
+        $property = null;
+        if (!empty($arguments['property'])) {
+            $property = $arguments['property'];
+        } elseif (!empty($arguments['renderingOptionProperty'])) {
+            $property = $arguments['renderingOptionProperty'];
+        }
+
+        if ($formRuntime === null) {
+            /** @var RendererInterface $fluidFormRenderer */
+            $fluidFormRenderer = $renderingContext->getViewHelperVariableContainer()->getView();
+            $formRuntime = $fluidFormRenderer->getFormRuntime();
+        }
+
+        return TranslationService::getInstance()->translateFormElementValue($element, $property, $formRuntime);
+    }
+}
diff --git a/typo3/sysext/form/Configuration/Backend/AjaxRoutes.php b/typo3/sysext/form/Configuration/Backend/AjaxRoutes.php
deleted file mode 100644
index 660792b6c3ab6a92bc9eb146fde6d2eba38c9209..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/Backend/AjaxRoutes.php
+++ /dev/null
@@ -1,13 +0,0 @@
-<?php
-use TYPO3\CMS\Form\Controller\WizardController;
-
-/**
- * Definitions for AJAX routes provided by EXT:form
- */
-return [
-    // Save the current form wizard
-    'formwizard_save' => [
-        'path' => '/wizard/form/save',
-        'target' => WizardController::class . '::saveAction'
-    ],
-];
diff --git a/typo3/sysext/form/Configuration/FlexForms/FormFramework.xml b/typo3/sysext/form/Configuration/FlexForms/FormFramework.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b8b9dab0418b46fc4aa62980e62c03aca4bd407b
--- /dev/null
+++ b/typo3/sysext/form/Configuration/FlexForms/FormFramework.xml
@@ -0,0 +1,40 @@
+<T3DataStructure>
+    <sheets>
+        <sDEF>
+            <ROOT>
+                <TCEforms>
+                    <sheetTitle>LLL:EXT:form/Resources/Private/Language/Database.xlf:tt_content.pi_flexform.formframework.sheet_general</sheetTitle>
+                </TCEforms>
+                <type>array</type>
+                <el>
+                    <settings.persistenceIdentifier>
+                        <TCEforms>
+                            <label>LLL:EXT:form/Resources/Private/Language/Database.xlf:tt_content.pi_flexform.formframework.persistenceIdentifier</label>
+                            <onChange>reload</onChange>
+                            <config>
+                                <type>select</type>
+                                <items>
+                                    <numIndex index="0" type="array">
+                                        <numIndex index="0">LLL:EXT:form/Resources/Private/Language/Database.xlf:tt_content.pi_flexform.formframework.selectPersistenceIdentifier</numIndex>
+                                        <numIndex index="1"></numIndex>
+                                    </numIndex>
+                                </items>
+                                <softref>formPersistenceIdentifier</softref>
+                            </config>
+                        </TCEforms>
+                    </settings.persistenceIdentifier>
+                    <settings.overrideFinishers>
+                        <TCEforms>
+                            <label>LLL:EXT:form/Resources/Private/Language/Database.xlf:tt_content.pi_flexform.formframework.overrideFinishers</label>
+                            <displayCond>FIELD:settings.persistenceIdentifier:REQ:TRUE</displayCond>
+                            <onChange>reload</onChange>
+                            <config>
+                                <type>check</type>
+                            </config>
+                        </TCEforms>
+                    </settings.overrideFinishers>
+                </el>
+            </ROOT>
+        </sDEF>
+    </sheets>
+</T3DataStructure>
diff --git a/typo3/sysext/form/Configuration/PageTS/modWizards.ts b/typo3/sysext/form/Configuration/PageTS/modWizards.ts
index aa514e38263e5363c7c0a01d1930c0013580373a..86a93700c9b2fd2b1b5fd0638b365fa60eb69463 100644
--- a/typo3/sysext/form/Configuration/PageTS/modWizards.ts
+++ b/typo3/sysext/form/Configuration/PageTS/modWizards.ts
@@ -1,367 +1,17 @@
 mod.wizards {
-	newContentElement.wizardItems {
-		forms {
-			show :=addToList(mailform)
-			elements {
-				mailform {
-					iconIdentifier = content-elements-mailform
-					title = LLL:EXT:backend/Resources/Private/Language/locallang_db_new_content_el.xlf:forms_mail_title
-					description = LLL:EXT:backend/Resources/Private/Language/locallang_db_new_content_el.xlf:forms_mail_description
-					tt_content_defValues {
-						CType = mailform
-						bodytext (
-enctype = multipart/form-data
-method = post
-prefix = tx_form
-						)
-					}
-				}
-			}
-		}
-	}
-
-	form {
-		defaults {
-			showTabs = elements, options, form
-			tabs {
-				elements {
-					showAccordions = basic, predefined, content
-					accordions {
-						basic {
-							showButtons = textline, textarea, checkbox, radio, select, fileupload, hidden, password, fieldset, submit, reset, button
-						}
-						predefined {
-							showButtons = name, email, checkboxgroup, radiogroup
-						}
-						content {
-							showButtons = header, textblock
-						}
-					}
-				}
-
-				options {
-					showAccordions = legend, label, attributes, options, validation, filters, various
-					accordions {
-						label {
-							showProperties = label
-						}
-						attributes {
-							showProperties = accept, accept-charset, accesskey, action, alt, autocomplete, autofocus, checked, class, cols, contenteditable, contextmenu, dir, draggable, dropzone, disabled, enctype, hidden, height, id, inputmode, label, lang, list, max, maxlength, method, min, minlength, multiple, name, novalidate, pattern, placeholder, readonly, required, rows, selected, selectionDirection, selectionEnd, selectionStart, size, spellcheck, src, step, style, tabindex, text, title, translate, type, value, width, wrap
-						}
-						validation {
-							showRules = alphabetic, alphanumeric, between, date, digit, email, equals, fileallowedtypes, filemaximumsize, fileminimumsize, float, greaterthan, inarray, integer, ip, length, lessthan, regexp, required, uri
-
-							rules {
-								alphabetic {
-									showProperties = message, error, showMessage, allowWhiteSpace
-								}
-
-								alphanumeric {
-									showProperties = message, error, showMessage, allowWhiteSpace
-								}
-
-								between {
-									showProperties = message, error, showMessage, minimum, maximum, inclusive
-								}
-
-								date {
-									showProperties = message, error, showMessage, format
-								}
-
-								digit {
-									showProperties = message, error, showMessage
-								}
-
-								email {
-									showProperties = message, error, showMessage
-								}
-
-								equals {
-									showProperties = message, error, showMessage, field
-								}
-
-								fileallowedtypes {
-									showProperties = message, error, showMessage, types
-								}
-
-								filemaximumsize {
-									showProperties = message, error, showMessage, maximum
-								}
-
-								fileminimumsize {
-									showProperties = message, error, showMessage, minimum
-								}
-
-								float {
-									showProperties = message, error, showMessage
-								}
-
-								greaterthan {
-									showProperties = message, error, showMessage, minimum
-								}
-
-								inarray {
-									showProperties = message, error, showMessage, array, strict
-								}
-
-								integer {
-									showProperties = message, error, showMessage
-								}
-
-								ip {
-									showProperties = message, error, showMessage
-								}
-
-								length {
-									showProperties = message, error, showMessage, minimum, maximum
-								}
-
-								lessthan {
-									showProperties = message, error, showMessage, maximum
-								}
-
-								regexp {
-									showProperties = message, error, showMessage, expression
-								}
-
-								required {
-									showProperties = message, error, showMessage
-								}
-
-								uri {
-									showProperties = message, error, showMessage
-								}
-							}
-						}
-						filtering {
-							showFilters = alphabetic, alphanumeric, currency, digit, integer, lowercase, regexp, stripnewlines, titlecase, trim, uppercase
-
-							filters {
-								alphabetic {
-									showProperties = allowWhiteSpace
-								}
-
-								alphanumeric {
-									showProperties = allowWhiteSpace
-								}
-
-								currency {
-									showProperties = decimalPoint, thousandSeparator
-								}
-
-								digit {
-									showProperties =
-								}
-
-								integer {
-									showProperties =
-								}
-
-								lowercase {
-									showProperties =
-								}
-
-								regexp {
-									showProperties = expression
-								}
-
-								stripnewlines {
-									showProperties =
-								}
-
-								titlecase {
-									showProperties =
-								}
-
-								trim {
-									showProperties = characterList
-								}
-
-								uppercase {
-									showProperties =
-								}
-							}
-						}
-					}
-				}
-
-				form {
-					showAccordions = behaviour, prefix, attributes, postProcessor
-					accordions {
-						postProcessor {
-							showPostProcessors = mail, redirect
-							postProcessors {
-								mail {
-									showProperties = recipientEmail, senderEmail, subject
-								}
-								redirect {
-									showProperties = destination
-								}
-							}
-						}
-					}
-				}
-			}
-		}
-
-		elements {
-			form {
-				accordions {
-					attributes {
-						showProperties = accept, action, dir, enctype, lang, method, novalidate, class, id, style, title
-					}
-				}
-			}
-
-			button {
-				showAccordions = label, attributes
-				accordions {
-					attributes {
-						showProperties = name, value, class, id
-					}
-				}
-			}
-
-			checkbox {
-				showAccordions = label, attributes, validation
-				accordions {
-					attributes {
-						showProperties = name, value, class, id, checked, required
-					}
-					validation {
-						showRules = required
-					}
-				}
-			}
-
-			fieldset {
-				showAccordions = legend, attributes
-				accordions {
-					attributes {
-						showProperties = class, id
-					}
-				}
-			}
-
-			fileupload {
-				showAccordions = label, attributes, validation
-				accordions {
-					attributes {
-						showProperties = name, class, id, required
-					}
-					validation {
-						showRules = required, fileallowedtypes, filemaximumsize, fileminimumsize
-					}
-				}
-			}
-
-			hidden {
-				showAccordions = attributes
-				accordions {
-					attributes {
-						showProperties = name, value
-					}
-				}
-			}
-
-			password {
-				showAccordions = label, attributes, validation
-				accordions {
-					attributes {
-						showProperties = name, placeholder, class, id, autocomplete, required
-					}
-					validation {
-						showRules = required, equals
-					}
-				}
-			}
-
-			radio < .checkbox
-
-			reset < .button
-			reset {
-				accordions {
-					attributes {
-						showProperties := removeFromList(name)
-					}
-				}
-			}
-
-			select {
-				showAccordions = label, attributes, options, validation
-				accordions {
-					attributes {
-						showProperties = name, size, class, id, multiple, required
-					}
-					validation {
-						showRules = required
-					}
-				}
-			}
-
-			submit < .button
-			submit {
-				accordions {
-					attributes {
-						showProperties := removeFromList(name)
-					}
-				}
-			}
-
-			textarea {
-				showAccordions = label, attributes, validation, filters
-				accordions {
-					attributes {
-						showProperties = name, placeholder, cols, rows, class, id, required, text
-					}
-					filtering {
-						showFilters = alphabetic, alphanumeric, lowercase, regexp, stripnewlines, titlecase, trim, uppercase
-					}
-					validation {
-						showRules = alphabetic, alphanumeric, length, regexp, required
-					}
-				}
-			}
-
-			textline {
-				showAccordions = label, attributes, validation, filters
-				accordions {
-					attributes {
-						showProperties = name, placeholder, type, class, id, autocomplete, required
-					}
-					validation {
-						showRules = alphabetic, alphanumeric, between, date, digit, email, equals, float, greaterthan, inarray, integer, ip, length, lessthan, regexp, required, uri
-					}
-					filtering {
-						showFilters = alphabetic, alphanumeric, currency, digit, integer, lowercase, regexp, titlecase, trim, uppercase
-					}
-				}
-			}
-
-			name {
-				showAccordions = legend, various
-			}
-
-			email < .textline
-
-			checkboxgroup {
-				showAccordions = legend, options, various, validation
-				accordions {
-					validation {
-						showRules = required
-					}
-				}
-			}
-
-			radiogroup < .checkboxgroup
-
-			header {
-				showAccordions = various
-			}
-
-			textblock {
-				showAccordions = various
-			}
-		}
-	}
+    newContentElement.wizardItems {
+        forms {
+            show :=addToList(formframework)
+            elements {
+                formframework {
+                    iconIdentifier = content-elements-mailform
+                    title = LLL:EXT:backend/Resources/Private/Language/locallang_db_new_content_el.xlf:forms_mail_title
+                    description = LLL:EXT:backend/Resources/Private/Language/locallang_db_new_content_el.xlf:forms_mail_description
+                    tt_content_defValues {
+                        CType = form_formframework
+                    }
+                }
+            }
+        }
+    }
 }
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TCA/Overrides/sys_template.php b/typo3/sysext/form/Configuration/TCA/Overrides/sys_template.php
deleted file mode 100644
index 6d53f0320ee2e2b0d4e40fcd97d7949ab5321b5d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TCA/Overrides/sys_template.php
+++ /dev/null
@@ -1,5 +0,0 @@
-<?php
-defined('TYPO3_MODE') or die();
-
-// Register static TypoScript resource
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile('form', 'Configuration/TypoScript/', 'Default TS');
diff --git a/typo3/sysext/form/Configuration/TCA/Overrides/tt_content.php b/typo3/sysext/form/Configuration/TCA/Overrides/tt_content.php
index 00b0d95497b3fdf661230f5c2fd7a8d08097562a..99ec0cd67be51141a920b0c1bddd1e1c4a8a76f1 100644
--- a/typo3/sysext/form/Configuration/TCA/Overrides/tt_content.php
+++ b/typo3/sysext/form/Configuration/TCA/Overrides/tt_content.php
@@ -1,121 +1,30 @@
 <?php
 defined('TYPO3_MODE') or die();
 
-// add an CType element "mailform"
-$GLOBALS['TCA']['tt_content']['ctrl']['typeicon_classes']['mailform'] = 'mimetypes-x-content-form';
-
-// check if there is already a forms tab and add the item after that, otherwise
-// add the tab item as well
-$additionalCTypeItem = [
-    'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:CType.I.8',
-    'mailform',
-    'content-elements-mailform'
-];
-
-$existingCTypeItems = $GLOBALS['TCA']['tt_content']['columns']['CType']['config']['items'];
-$groupFound = false;
-$groupPosition = false;
-foreach ($existingCTypeItems as $position => $item) {
-    if ($item[0] === 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:CType.div.forms') {
-        $groupFound = true;
-        $groupPosition = $position;
-        break;
-    }
-}
-
-if ($groupFound && $groupPosition) {
-    // add the new CType item below CType
-    array_splice($GLOBALS['TCA']['tt_content']['columns']['CType']['config']['items'], $groupPosition+1, 0, [0 => $additionalCTypeItem]);
-} else {
-    // nothing found, add two items (group + new CType) at the bottom of the list
-    \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem('tt_content', 'CType',
-        ['LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:CType.div.forms', '--div--']
+call_user_func(function () {
+    // Add the FlexForm
+    \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
+        '*',
+        'FILE:EXT:form/Configuration/FlexForms/FormFramework.xml',
+        'form_formframework'
     );
-    \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem('tt_content', 'CType', $additionalCTypeItem);
-}
-
-// predefined forms
-\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns(
-    'tt_content',
-    [
-        'tx_form_predefinedform' => [
-            'label' => 'LLL:EXT:form/Resources/Private/Language/Database.xlf:tx_form_predefinedform',
-            'exclude' => true,
-            'config' => [
-                'type' => 'select',
-                'renderType' => 'selectSingle',
-                'items' => [
-                    [
-                        'LLL:EXT:form/Resources/Private/Language/Database.xlf:tx_form_predefinedform.selectPredefinedForm',
-                        ''
-                    ],
-                ],
-            ],
-        ],
-    ]
-);
-$GLOBALS['TCA']['tt_content']['ctrl']['requestUpdate'] .= ',tx_form_predefinedform';
-
-// Hide bodytext if a predefined form is selected
-$GLOBALS['TCA']['tt_content']['columns']['bodytext']['displayCond']['AND'] = [
-    'OR' => [
-        'FIELD:CType:!=:mailform',
-        'AND' => [
-            'FIELD:CType:=:mailform',
-            'FIELD:tx_form_predefinedform:REQ:false',
-        ],
-    ],
-];
 
-$GLOBALS['TCA']['tt_content']['columns']['bodytext']['config']['wizards']['forms'] = [
-    'notNewRecords' => true,
-    'enableByTypeConfig' => 1,
-    'type' => 'script',
-    'title' => 'Form wizard',
-    'icon' => 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_forms.gif',
-    'module' => [
-        'name' => 'wizard_form'
-    ],
-    'params' => [
-        'xmlOutput' => 0
-    ]
-];
-
-// Add palettes if they are not available
-if (!isset($GLOBALS['TCA']['tt_content']['palettes']['visibility'])) {
-    $GLOBALS['TCA']['tt_content']['palettes']['visibility'] = [
-        'showitem' => '
-            hidden;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:hidden_formlabel,
-            sectionIndex;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:sectionIndex_formlabel,
-            linkToTop;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:linkToTop_formlabel
-        ',
-    ];
-}
-
-if (!isset($GLOBALS['TCA']['tt_content']['palettes']['frames'])) {
-    $GLOBALS['TCA']['tt_content']['palettes']['frames'] = [
-        'showitem' => '
-            layout;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:layout_formlabel
-        ',
-    ];
-}
-
-$GLOBALS['TCA']['tt_content']['types']['mailform']['showitem'] = '
-	--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.general;general,
-	--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.header;header,rowDescription,
-	--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:CType.I.8,
-		bodytext;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:bodytext.ALT.mailform,
-		tx_form_predefinedform;LLL:EXT:form/Resources/Private/Language/Database.xlf:tx_form_predefinedform,
-	--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,
-		--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.frames;frames,
-	--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access,
-		--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.visibility;visibility,
-		--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.access;access,
-';
-if (!is_array($GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides'])) {
-    $GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides'] = [];
-}
-if (!is_array($GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides']['bodytext'])) {
-    $GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides']['bodytext'] = [];
-}
-$GLOBALS['TCA']['tt_content']['types']['mailform']['columnsOverrides']['bodytext']['config']['renderType'] = 'formwizard';
+    $GLOBALS['TCA']['tt_content']['types']['form_formframework']['showitem'] =
+        '--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.general;general,'
+        . '--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.header;header,rowDescription,'
+        . '--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.plugin,pi_flexform,'
+        . '--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access,'
+        . '--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.visibility;visibility,'
+        . '--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.access;access,'
+        . '--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,'
+        . '--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:palette.frames;frames,'
+        . '--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.behaviour,'
+        . '--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.extended';
+
+    // Register the plugin
+    \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
+        'TYPO3.CMS.Form',
+        'Formframework',
+        'Form'
+    );
+});
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Button.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Button.ts
deleted file mode 100644
index 7cec6af661dcd17a863dcf955bf8c58b278f9fd8..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Button.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			BUTTON {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/Button
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# BUTTON
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:form.button
-				#
-				# A historical element which generates a <input type="button" /> tag.
-				# To be compatible it is a copy of the new element INPUTTYPEBUTTON
-				# If you want to use a <button> tag you have to use
-				# BUTTON =< .BUTTONTAG or use the BUTTONTAG directly
-			BUTTON =< .INPUTTYPEBUTTON
-			BUTTON {
-				partialPath =< plugin.tx_form.view.elementPartials.INPUTTYPEBUTTON.10.partialPath
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Buttontag.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Buttontag.ts
deleted file mode 100644
index a4ce6f5cf219de90e5d08acc1b076d876b8c7ca5..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Buttontag.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			BUTTONTAG {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/ButtonTag
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# BUTTONTAG
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:form.button
-				#
-				# Generates an element <button type="..." />
-			BUTTONTAG {
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-					160 = translate
-						# element specific attributes
-					200 = autofocus
-					210 = disabled
-					220 = name
-					230 = type
-					240 = value
-				}
-
-					# htmlAttributesUsedByTheViewHelperDirectly
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# Each HTML attribute defined at ".htmlAttributes" is available as array within the model.
-					# This array will be added to the resulting HTML tag.
-					# For this purpose the Fluid argument "additionalAttributes" of the ViewHelper is used.
-					#
-					# Some HTML attributes have to be assigned directly as an argument to the ViewHelper.
-					# The htmlAttributesUsedByTheViewHelperDirectly map is used to remove the specified
-					# HTML attribute from the "htmlAttributes" array and sets it for the model's "additionalArguments" array.
-					#
-					# There are two attributes which special behavior:
-					# 	* disabled
-					#	* readonly
-					# These attributes can be assigned to the most ViewHelpers but whenever a "disabled" attribute appears
-					# the browser will disable this element no matter of the value.
-					# See: https://forge.typo3.org/issues/42474
-					# Therefore it is held in the htmlAttributes array and the code removes this attribute if its value is set to 0.
-				htmlAttributesUsedByTheViewHelperDirectly {
-						# generic attributes
-					10 = class
-					20 = dir
-					30 = id
-					40 = lang
-					50 = style
-					60 = title
-					70 = accesskey
-					80 = tabindex
-					90 = onclick
-					100 = name
-					110 = value
-						# ButtonViewHelper
-					120 = autofocus
-					130 = type
-				}
-
-					# defaultHtmlAttributeValues
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# The following values are automatically set if there is no entry in the user configured element.
-				defaultHtmlAttributeValues {
-					type = button
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.BUTTONTAG.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 0
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 0
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Checkbox.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Checkbox.ts
deleted file mode 100644
index 5f2ecfb83ab9fa756d7866e1382305e4bd68ff9a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Checkbox.ts
+++ /dev/null
@@ -1,147 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			CHECKBOX {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/Checkbox
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# CHECKBOX
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:form.checkbox
-				#
-				# @ToDo: add more details
-			CHECKBOX {
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-					160 = translate
-						# element specific attributes
-					200 = type
-					210 = autofocus
-					220 = checked
-					230 = disabled
-					240 = name
-					250 = readonly
-					260 = required
-					270 = value
-				}
-
-					# fixedHtmlAttributeValues
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# The following values are automatically set as attributes.
-				fixedHtmlAttributeValues {
-					type = checkbox
-				}
-
-					# htmlAttributesUsedByTheViewHelperDirectly
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# Each HTML attribute defined at ".htmlAttributes" is available as array within the model.
-					# This array will be added to the resulting HTML tag.
-					# For this purpose the Fluid argument "additionalAttributes" of the ViewHelper is used.
-					#
-					# Some HTML attributes have to be assigned directly as an argument to the ViewHelper.
-					# The htmlAttributesUsedByTheViewHelperDirectly map is used to remove the specified
-					# HTML attribute from the "htmlAttributes" array and sets it for the model's "additionalArguments" array.
-					#
-					# There are two attributes which special behavior:
-					# 	* disabled
-					#	* readonly
-					# These attributes can be assigned to the most ViewHelpers but whenever a "disabled" attribute appears
-					# the browser will disable this element no matter of the value.
-					# See: https://forge.typo3.org/issues/42474
-					# Therefore it is held in the htmlAttributes array and the code removes this attribute if its value is set to 0.
-				htmlAttributesUsedByTheViewHelperDirectly {
-						# generic attributes
-					10 = class
-					20 = dir
-					30 = id
-					40 = lang
-					50 = style
-					60 = title
-					70 = accesskey
-					80 = tabindex
-					90 = onclick
-					100 = name
-					110 = value
-						# CheckboxViewHelper
-					120 = checked
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.CHECKBOX.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 1
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 1
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Checkboxgroup.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Checkboxgroup.ts
deleted file mode 100644
index fc079b2e885ac98d1dbbaed7dd428376c0e1b72c..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Checkboxgroup.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			CHECKBOXGROUP {
-				10 {
-					displayName = Default
-					partialPath = ContainerElements/Checkboxgroup
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# CHECKBOXGROUP
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: none
-				#
-				# This defines a container element.
-				# @ToDo: add more details
-			CHECKBOXGROUP =< .FIELDSET
-			CHECKBOXGROUP {
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.CHECKBOXGROUP.10.partialPath
-
-					# childrenInheritName
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# If set to 1 all child elements inherit the name of the parent element.
-					# @ToDo: add more details
-				childrenInheritName = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 1
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 1
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Contentelement.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Contentelement.ts
deleted file mode 100644
index 871984870c94028c2bad39e24612e9b37661a256..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Contentelement.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-				# useless for the wizard but needed for the frontend
-			CONTENTELEMENT {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/ContentElement
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# CONTENTELEMENT
-				# Used by: frontend
-				# Used ViewHelper: none
-				#
-				# This defines an internal element which holds some basic configuration
-				# like visibility settings and the used partial path.
-				#
-				# @ToDo: add more details
-			CONTENTELEMENT {
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.CONTENTELEMENT.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 0
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 0
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Fieldset.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Fieldset.ts
deleted file mode 100644
index 2f273285b174cdc66e38537e7aabe61319122a89..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Fieldset.ts
+++ /dev/null
@@ -1,96 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			FIELDSET {
-				10 {
-					displayName = Default
-					partialPath = ContainerElements/Fieldset
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# FIELDSET
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: none
-				#
-				# This defines a container element.
-				# @ToDo: add more details
-			FIELDSET {
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-						# element specific attributes
-					200 = disabled
-					210 = name
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.FIELDSET.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 0
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 0
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Fileupload.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Fileupload.ts
deleted file mode 100644
index 065586cb4b189636ff4135177d62acadc025a4f0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Fileupload.ts
+++ /dev/null
@@ -1,148 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			FILEUPLOAD {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/Upload
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# FILEUPLOAD
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:form.upload
-				#
-				# @ToDo: add more details
-			FILEUPLOAD {
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-					160 = translate
-						# element specific attributes
-					200 = type
-					210 = accept
-					220 = autofocus
-					230 = disabled
-					240 = multiple
-					250 = name
-					260 = readonly
-					270 = required
-					280 = value
-				}
-
-					# fixedHtmlAttributeValues
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# The following values are automatically set as attributes.
-				fixedHtmlAttributeValues {
-					type = file
-				}
-
-					# htmlAttributesUsedByTheViewHelperDirectly
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# Each HTML attribute defined at ".htmlAttributes" is available as array within the model.
-					# This array will be added to the resulting HTML tag.
-					# For this purpose the Fluid argument "additionalAttributes" of the ViewHelper is used.
-					#
-					# Some HTML attributes have to be assigned directly as an argument to the ViewHelper.
-					# The htmlAttributesUsedByTheViewHelperDirectly map is used to remove the specified
-					# HTML attribute from the "htmlAttributes" array and sets it for the model's "additionalArguments" array.
-					#
-					# There are two attributes which special behavior:
-					# 	* disabled
-					#	* readonly
-					# These attributes can be assigned to the most ViewHelpers but whenever a "disabled" attribute appears
-					# the browser will disable this element no matter of the value.
-					# See: https://forge.typo3.org/issues/42474
-					# Therefore it is held in the htmlAttributes array and the code removes this attribute if its value is set to 0.
-				htmlAttributesUsedByTheViewHelperDirectly {
-						# generic attributes
-					10 = class
-					20 = dir
-					30 = id
-					40 = lang
-					50 = style
-					60 = title
-					70 = accesskey
-					80 = tabindex
-					90 = onclick
-					100 = name
-					110 = value
-						# UploadViewHelper
-					120 = multiple
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.FILEUPLOAD.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 1
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 1
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Form.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Form.ts
deleted file mode 100644
index 1ededb98bdf67f0242efc390124075be3b453bc0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Form.ts
+++ /dev/null
@@ -1,166 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			FORM {
-				10 {
-					displayName = Default
-					partialPath = ContainerElements/Form
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# FORM
-				# Used by: frontend, wizard (not implemented right now)
-				# Overwritable by user: TRUE
-				# Used ViewHelper: f:form
-				#
-				# @ToDo: add more details
-			FORM {
-					# themeName
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# Sets the theme name used for templating.
-					# Right now there is one default theme. One can define an own theme and use this one instead.
-					#
-					# This setting can be overwritten in the FORM object.
-					# @ToDo: add more details
-				themeName = Default
-
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-					160 = translate
-						# element specific attributes
-					200 = action
-					210 = accept
-					220 = accept-charset
-					230 = autocomplete
-					240 = enctype
-					250 = method
-					260 = name
-					270 = novalidate
-					280 = target
-				}
-
-					# defaultHtmlAttributeValues
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# The following values are automatically set if there is no entry in the user configured element.
-				defaultHtmlAttributeValues {
-					enctype = multipart/form-data
-					method = post
-				}
-
-					# fixedHtmlAttributeValues
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# The following values are automatically set as attributes.
-				fixedHtmlAttributeValues =
-
-					# htmlAttributesUsedByTheViewHelperDirectly
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# Each HTML attribute defined at ".htmlAttributes" is available as array within the model.
-					# This array will be added to the resulting HTML tag.
-					# For this purpose the Fluid argument "additionalAttributes" of the ViewHelper is used.
-					#
-					# Some HTML attributes have to be assigned directly as an argument to the ViewHelper.
-					# The htmlAttributesUsedByTheViewHelperDirectly map is used to remove the specified
-					# HTML attribute from the "htmlAttributes" array and sets it for the model's "additionalArguments" array.
-					#
-					# There are two attributes which special behavior:
-					# 	* disabled
-					#	* readonly
-					# These attributes can be assigned to the most ViewHelpers but whenever a "disabled" attribute appears
-					# the browser will disable this element no matter of the value.
-					# See: https://forge.typo3.org/issues/42474
-					# Therefore it is held in the htmlAttributes array and the code removes this attribute if its value is set to 0.
-				htmlAttributesUsedByTheViewHelperDirectly {
-						# generic attributes
-					10 = class
-					20 = dir
-					30 = id
-					40 = lang
-					50 = style
-					60 = title
-					70 = accesskey
-					80 = tabindex
-						# FormViewHelper
-					90 = enctype
-					100 = method
-					110 = name
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.FORM.10.partialPath
-
-					# viewHelperDefaultArguments
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# This helper array is used to cast some values needed by the ViewHelpers.
-					# E.g the f:form ViewHelper needs an array for the
-					# argument "additionalParams". If additionalParams is not set
-					# in the userdefined TypoScript this results in a NULL value in the
-					# templating variable "{model.additionalArguments.additionalParams}"
-					# and this throws an error. Most of the ViewHelper arguments
-					# are strings and/ or can handle such NULL values but there are some
-					# ViewHelpers which need some type casting.
-				viewHelperDefaultArguments {
-					arguments {
-					}
-
-					additionalParams {
-					}
-
-					argumentsToBeExcludedFromQueryString {
-					}
-				}
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Header.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Header.ts
deleted file mode 100644
index fc7ea71872ebb588cdc838e85ee182e316b7f3da..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Header.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			HEADER {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/Header
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# HEADER
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:format.raw
-				#
-				# @ToDo: add more details
-			HEADER {
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.HEADER.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 0
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 0
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Hidden.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Hidden.ts
deleted file mode 100644
index c33c1edad4a85dc4c342358f064d48f6ded0fc20..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Hidden.ts
+++ /dev/null
@@ -1,140 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			HIDDEN {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/Hidden
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# HIDDEN
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:form.hidden
-				#
-				# @ToDo: add more details
-			HIDDEN {
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-					160 = translate
-						# element specific attributes
-					200 = type
-					210 = name
-					220 = value
-				}
-
-					# fixedHtmlAttributeValues
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# The following values are automatically set as attributes.
-				fixedHtmlAttributeValues {
-					type = hidden
-				}
-
-					# htmlAttributesUsedByTheViewHelperDirectly
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# Each HTML attribute defined at ".htmlAttributes" is available as array within the model.
-					# This array will be added to the resulting HTML tag.
-					# For this purpose the Fluid argument "additionalAttributes" of the ViewHelper is used.
-					#
-					# Some HTML attributes have to be assigned directly as an argument to the ViewHelper.
-					# The htmlAttributesUsedByTheViewHelperDirectly map is used to remove the specified
-					# HTML attribute from the "htmlAttributes" array and sets it for the model's "additionalArguments" array.
-					#
-					# There are two attributes which special behavior:
-					# 	* disabled
-					#	* readonly
-					# These attributes can be assigned to the most ViewHelpers but whenever a "disabled" attribute appears
-					# the browser will disable this element no matter of the value.
-					# See: https://forge.typo3.org/issues/42474
-					# Therefore it is held in the htmlAttributes array and the code removes this attribute if its value is set to 0.
-				htmlAttributesUsedByTheViewHelperDirectly {
-						# generic attributes
-					10 = class
-					20 = dir
-					30 = id
-					40 = lang
-					50 = style
-					60 = title
-					70 = accesskey
-					80 = tabindex
-					90 = onclick
-					100 = name
-					110 = value
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.HIDDEN.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 0
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 0
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Input.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Input.ts
deleted file mode 100644
index 03017f165caf3d71f05aadbe9acdcd634467fd5b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Input.ts
+++ /dev/null
@@ -1,168 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			INPUT {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/Input
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# INPUT
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:form.textfield
-				#
-				# @ToDo: add more details
-			INPUT {
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-					160 = translate
-						# element specific attributes
-					200 = type
-					210 = accept
-					220 = autocomplete
-					230 = autofocus
-					240 = checked
-					250 = disabled
-					260 = list
-					270 = inputmode
-					280 = max
-					290 = maxlength
-					300 = min
-					310 = minlength
-					320 = multiple
-					330 = name
-					340 = pattern
-					350 = placeholder
-					360 = readonly
-					370 = required
-					380 = size
-					390 = src
-					400 = step
-					410 = value
-					420 = width
-				}
-
-					# htmlAttributesUsedByTheViewHelperDirectly
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# Each HTML attribute defined at ".htmlAttributes" is available as array within the model.
-					# This array will be added to the resulting HTML tag.
-					# For this purpose the Fluid argument "additionalAttributes" of the ViewHelper is used.
-					#
-					# Some HTML attributes have to be assigned directly as an argument to the ViewHelper.
-					# The htmlAttributesUsedByTheViewHelperDirectly map is used to remove the specified
-					# HTML attribute from the "htmlAttributes" array and sets it for the model's "additionalArguments" array.
-					#
-					# There are two attributes which special behavior:
-					# 	* disabled
-					#	* readonly
-					# These attributes can be assigned to the most ViewHelpers but whenever a "disabled" attribute appears
-					# the browser will disable this element no matter of the value.
-					# See: https://forge.typo3.org/issues/42474
-					# Therefore it is held in the htmlAttributes array and the code removes this attribute if its value is set to 0.
-				htmlAttributesUsedByTheViewHelperDirectly {
-						# generic attributes
-					10 = class
-					20 = dir
-					30 = id
-					40 = lang
-					50 = style
-					60 = title
-					70 = accesskey
-					80 = tabindex
-					90 = onclick
-					100 = name
-					110 = value
-						# TextfieldViewHelper
-					120 = autofocus
-					130 = maxlength
-					140 = size
-					150 = placeholder
-					160 = pattern
-					170 = required
-					180 = type
-				}
-
-					# defaultHtmlAttributeValues
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# The following values are automatically set if there is no entry in the user configured element.
-				defaultHtmlAttributeValues {
-					type = text
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.INPUT.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 1
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 1
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Inputtypebutton.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Inputtypebutton.ts
deleted file mode 100644
index 5c674eb5f6e909223574c4b359bfe0ae0b6718bc..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Inputtypebutton.ts
+++ /dev/null
@@ -1,144 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			INPUTTYPEBUTTON {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/InputTypeButton
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# INPUTTYPEBUTTON
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:form.textfield
-				#
-				# Generates an element <input type="button" />
-			INPUTTYPEBUTTON {
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-					160 = translate
-						# element specific attributes
-					200 = type
-					210 = autofocus
-					220 = disabled
-					230 = name
-					240 = value
-				}
-
-					# fixedHtmlAttributeValues
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# The following values are automatically set as attributes.
-				fixedHtmlAttributeValues {
-					type = button
-				}
-
-					# htmlAttributesUsedByTheViewHelperDirectly
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# Each HTML attribute defined at ".htmlAttributes" is available as array within the model.
-					# This array will be added to the resulting HTML tag.
-					# For this purpose the Fluid argument "additionalAttributes" of the ViewHelper is used.
-					#
-					# Some HTML attributes have to be assigned directly as an argument to the ViewHelper.
-					# The htmlAttributesUsedByTheViewHelperDirectly map is used to remove the specified
-					# HTML attribute from the "htmlAttributes" array and sets it for the model's "additionalArguments" array.
-					#
-					# There are two attributes which special behavior:
-					# 	* disabled
-					#	* readonly
-					# These attributes can be assigned to the most ViewHelpers but whenever a "disabled" attribute appears
-					# the browser will disable this element no matter of the value.
-					# See: https://forge.typo3.org/issues/42474
-					# Therefore it is held in the htmlAttributes array and the code removes this attribute if its value is set to 0.
-				htmlAttributesUsedByTheViewHelperDirectly {
-						# generic attributes
-					10 = class
-					20 = dir
-					30 = id
-					40 = lang
-					50 = style
-					60 = title
-					70 = accesskey
-					80 = tabindex
-					90 = onclick
-					100 = name
-					110 = value
-						# TextfieldViewHelper
-					120 = type
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.INPUTTYPEBUTTON.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 0
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 0
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Label.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Label.ts
deleted file mode 100644
index 5a3afe02284b772123128b5160c3022ac7f6ccdb..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Label.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-				# special definitions for internal usage
-			LABEL {
-				10 {
-					displayName = Default
-					partialPath = AdditionalElements/Label
-				}
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Optgroup.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Optgroup.ts
deleted file mode 100644
index a30bf70512bd1d994de3fed7952492bf32798e36..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Optgroup.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-plugin.tx_form {
-	settings {
-		registeredElements {
-				# OPTGROUP
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: form:select (extends f:form.select)
-				#
-				# Element is needed to define select options via TypoScript but
-				# the rendering is based on the select ViewHelper.
-				# Therefore no special settings are needed.
-				#
-				# @ToDo: add more details
-			OPTGROUP {
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Option.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Option.ts
deleted file mode 100644
index cc84a4b2078e86b714cd4a64074dd26ba027428b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Option.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-plugin.tx_form {
-	settings {
-		registeredElements {
-				# OPTION
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: form:select (extends f:form.select)
-				#
-				# Element is needed to define select options via TypoScript but
-				# the rendering is based on the select ViewHelper.
-				# Therefore no special settings are needed.
-				#
-				# @ToDo: add more details
-			OPTION {
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Password.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Password.ts
deleted file mode 100644
index c364c2a22b96c17beeb8dc60b9f6b97aa907846c..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Password.ts
+++ /dev/null
@@ -1,153 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			PASSWORD {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/Password
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# PASSWORD
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:form.password
-				#
-				# @ToDo: add more details
-			PASSWORD {
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-					160 = translate
-						# element specific attributes
-					200 = type
-					210 = autocomplete
-					220 = autofocus
-					230 = disabled
-					240 = maxlength
-					250 = minlength
-					260 = name
-					270 = pattern
-					280 = placeholder
-					290 = readonly
-					300 = required
-					310 = size
-					320 = value
-				}
-
-					# fixedHtmlAttributeValues
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# The following values are automatically set as attributes.
-				fixedHtmlAttributeValues {
-					type = password
-				}
-
-					# htmlAttributesUsedByTheViewHelperDirectly
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# Each HTML attribute defined at ".htmlAttributes" is available as array within the model.
-					# This array will be added to the resulting HTML tag.
-					# For this purpose the Fluid argument "additionalAttributes" of the ViewHelper is used.
-					#
-					# Some HTML attributes have to be assigned directly as an argument to the ViewHelper.
-					# The htmlAttributesUsedByTheViewHelperDirectly map is used to remove the specified
-					# HTML attribute from the "htmlAttributes" array and sets it for the model's "additionalArguments" array.
-					#
-					# There are two attributes which special behavior:
-					# 	* disabled
-					#	* readonly
-					# These attributes can be assigned to the most ViewHelpers but whenever a "disabled" attribute appears
-					# the browser will disable this element no matter of the value.
-					# See: https://forge.typo3.org/issues/42474
-					# Therefore it is held in the htmlAttributes array and the code removes this attribute if its value is set to 0.
-				htmlAttributesUsedByTheViewHelperDirectly {
-						# generic attributes
-					10 = class
-					20 = dir
-					30 = id
-					40 = lang
-					50 = style
-					60 = title
-					70 = accesskey
-					80 = tabindex
-					90 = onclick
-					100 = name
-					110 = value
-						# PasswordViewHelper
-					120 = maxlength
-					130 = size
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.PASSWORD.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 0
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 0
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Radio.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Radio.ts
deleted file mode 100644
index 9cf918ef280ad986a50acbe894c186488eaa1874..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Radio.ts
+++ /dev/null
@@ -1,148 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			RADIO {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/Radio
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# RADIO
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:form.radio
-				#
-				# @ToDo: add more details
-			RADIO {
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-					160 = translate
-						# element specific attributes
-					200 = type
-					210 = autofocus
-					220 = checked
-					230 = disabled
-					240 = name
-					250 = readonly
-					260 = required
-					270 = value
-				}
-
-					# fixedHtmlAttributeValues
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# The following values are automatically set as attributes.
-				fixedHtmlAttributeValues {
-					type = radio
-				}
-
-					# htmlAttributesUsedByTheViewHelperDirectly
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# Each HTML attribute defined at ".htmlAttributes" is available as array within the model.
-					# This array will be added to the resulting HTML tag.
-					# For this purpose the Fluid argument "additionalAttributes" of the ViewHelper is used.
-					#
-					# Some HTML attributes have to be assigned directly as an argument to the ViewHelper.
-					# The htmlAttributesUsedByTheViewHelperDirectly map is used to remove the specified
-					# HTML attribute from the "htmlAttributes" array and sets it for the model's "additionalArguments" array.
-					#
-					# There are two attributes which special behavior:
-					# 	* disabled
-					#	* readonly
-					# These attributes can be assigned to the most ViewHelpers but whenever a "disabled" attribute appears
-					# the browser will disable this element no matter of the value.
-					# See: https://forge.typo3.org/issues/42474
-					# Therefore it is held in the htmlAttributes array and the code removes this attribute if its value is set to 0.
-				htmlAttributesUsedByTheViewHelperDirectly {
-						# generic attributes
-					10 = class
-					20 = dir
-					30 = id
-					40 = lang
-					50 = style
-					60 = title
-					70 = accesskey
-					80 = tabindex
-					90 = onclick
-					100 = name
-					110 = value
-					120 = multiple
-						# RadioViewHelper
-					130 = checked
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.RADIO.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 1
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 1
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Radiogroup.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Radiogroup.ts
deleted file mode 100644
index 9edbc46be52480027d28895fe52be215e33d3ee1..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Radiogroup.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			RADIOGROUP {
-				10 {
-					displayName = Default
-					partialPath = ContainerElements/Radiogroup
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# RADIOGROUP
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: none
-				#
-				# This defines a container element.
-				# @ToDo: add more details
-			RADIOGROUP =< .FIELDSET
-			RADIOGROUP {
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.RADIOGROUP.10.partialPath
-
-					# childrenInheritName
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# If set to 1 all child elements inherit the name of the parent element.
-					# @ToDo: add more details
-				childrenInheritName = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 1
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 1
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Reset.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Reset.ts
deleted file mode 100644
index 7a1ce431b00d39c4aac1f45ea3a197a506c80b53..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Reset.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			RESET {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/Reset
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# RESET
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:form.textfield
-				#
-				# @ToDo: add more details
-			RESET {
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-					160 = translate
-						# element specific attributes
-					200 = type
-					210 = autofocus
-					220 = disabled
-					230 = name
-					240 = value
-				}
-
-					# fixedHtmlAttributeValues
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# The following values are automatically set as attributes.
-				fixedHtmlAttributeValues {
-					type = reset
-				}
-
-					# htmlAttributesUsedByTheViewHelperDirectly
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# Each HTML attribute defined at ".htmlAttributes" is available as array within the model.
-					# This array will be added to the resulting HTML tag.
-					# For this purpose the Fluid argument "additionalAttributes" of the ViewHelper is used.
-					#
-					# Some HTML attributes have to be assigned directly as an argument to the ViewHelper.
-					# The htmlAttributesUsedByTheViewHelperDirectly map is used to remove the specified
-					# HTML attribute from the "htmlAttributes" array and sets it for the model's "additionalArguments" array.
-					#
-					# There are two attributes which special behavior:
-					# 	* disabled
-					#	* readonly
-					# These attributes can be assigned to the most ViewHelpers but whenever a "disabled" attribute appears
-					# the browser will disable this element no matter of the value.
-					# See: https://forge.typo3.org/issues/42474
-					# Therefore it is held in the htmlAttributes array and the code removes this attribute if its value is set to 0.
-				htmlAttributesUsedByTheViewHelperDirectly {
-						# generic attributes
-					10 = class
-					20 = dir
-					30 = id
-					40 = lang
-					50 = style
-					60 = title
-					70 = accesskey
-					80 = tabindex
-					90 = onclick
-					100 = name
-					110 = value
-						# TextfieldViewHelper
-					120 = autofocus
-					130 = type
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.RESET.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 0
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 0
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Select.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Select.ts
deleted file mode 100644
index be8760d804536e493dc8faf814dcc963026a9f67..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Select.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			SELECT {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/Select
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# SELECT
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: form:select (extends f:form.select)
-				#
-				# @ToDo: add more details
-			SELECT {
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-					160 = translate
-						# element specific attributes
-					200 = autofocus
-					210 = disabled
-					220 = multiple
-					230 = name
-					240 = required
-					250 = size
-				}
-
-					# htmlAttributesUsedByTheViewHelperDirectly
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# Each HTML attribute defined at ".htmlAttributes" is available as array within the model.
-					# This array will be added to the resulting HTML tag.
-					# For this purpose the Fluid argument "additionalAttributes" of the ViewHelper is used.
-					#
-					# Some HTML attributes have to be assigned directly as an argument to the ViewHelper.
-					# The htmlAttributesUsedByTheViewHelperDirectly map is used to remove the specified
-					# HTML attribute from the "htmlAttributes" array and sets it for the model's "additionalArguments" array.
-					#
-					# There are two attributes which special behavior:
-					# 	* disabled
-					#	* readonly
-					# These attributes can be assigned to the most ViewHelpers but whenever a "disabled" attribute appears
-					# the browser will disable this element no matter of the value.
-					# See: https://forge.typo3.org/issues/42474
-					# Therefore it is held in the htmlAttributes array and the code removes this attribute if its value is set to 0.
-				htmlAttributesUsedByTheViewHelperDirectly {
-						# generic attributes
-					10 = class
-					20 = dir
-					30 = id
-					40 = lang
-					50 = style
-					60 = title
-					70 = accesskey
-					80 = tabindex
-					90 = onclick
-					100 = name
-					110 = value
-						# SelectViewHelper
-					120 = multiple
-					130 = size
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.SELECT.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 1
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 1
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Submit.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Submit.ts
deleted file mode 100644
index 1965b63f140b872016a573ad14940f2a7d1acfa4..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Submit.ts
+++ /dev/null
@@ -1,141 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			SUBMIT {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/Submit
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# SUBMIT
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:form.submit
-				#
-				# @ToDo: add more details
-			SUBMIT {
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-					160 = translate
-						# element specific attributes
-					200 = type
-					210 = autofocus
-					220 = disabled
-					230 = name
-					240 = value
-				}
-
-					# fixedHtmlAttributeValues
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# The following values are automatically set as attributes.
-				fixedHtmlAttributeValues {
-					type = submit
-				}
-
-					# htmlAttributesUsedByTheViewHelperDirectly
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# Each HTML attribute defined at ".htmlAttributes" is available as array within the model.
-					# This array will be added to the resulting HTML tag.
-					# For this purpose the Fluid argument "additionalAttributes" of the ViewHelper is used.
-					#
-					# Some HTML attributes have to be assigned directly as an argument to the ViewHelper.
-					# The htmlAttributesUsedByTheViewHelperDirectly map is used to remove the specified
-					# HTML attribute from the "htmlAttributes" array and sets it for the model's "additionalArguments" array.
-					#
-					# There are two attributes which special behavior:
-					# 	* disabled
-					#	* readonly
-					# These attributes can be assigned to the most ViewHelpers but whenever a "disabled" attribute appears
-					# the browser will disable this element no matter of the value.
-					# See: https://forge.typo3.org/issues/42474
-					# Therefore it is held in the htmlAttributes array and the code removes this attribute if its value is set to 0.
-				htmlAttributesUsedByTheViewHelperDirectly {
-						# generic attributes
-					10 = dir
-					20 = id
-					30 = lang
-					40 = style
-					50 = title
-					60 = accesskey
-					70 = tabindex
-					80 = onclick
-					90 = name
-					100 = value
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.SUBMIT.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 0
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 0
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Textarea.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Textarea.ts
deleted file mode 100644
index c383e4dfa46370b150df0f1a3c2dc19d8f18042d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Textarea.ts
+++ /dev/null
@@ -1,148 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			TEXTAREA {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/Textarea
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# TEXTAREA
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:form.textarea
-				#
-				# @ToDo: add more details
-			TEXTAREA {
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-					160 = translate
-						# element specific attributes
-					200 = autofocus
-					210 = cols
-					220 = disabled
-					230 = inputmode
-					240 = maxlength
-					250 = minlength
-					260 = name
-					270 = placeholder
-					280 = readonly
-					290 = required
-					300 = rows
-					310 = selectionDirection
-					320 = selectionEnd
-					330 = selectionStart
-					340 = wrap
-				}
-
-					# htmlAttributesUsedByTheViewHelperDirectly
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# Each HTML attribute defined at ".htmlAttributes" is available as array within the model.
-					# This array will be added to the resulting HTML tag.
-					# For this purpose the Fluid argument "additionalAttributes" of the ViewHelper is used.
-					#
-					# Some HTML attributes have to be assigned directly as an argument to the ViewHelper.
-					# The htmlAttributesUsedByTheViewHelperDirectly map is used to remove the specified
-					# HTML attribute from the "htmlAttributes" array and sets it for the model's "additionalArguments" array.
-					#
-					# There are two attributes which special behavior:
-					# 	* disabled
-					#	* readonly
-					# These attributes can be assigned to the most ViewHelpers but whenever a "disabled" attribute appears
-					# the browser will disable this element no matter of the value.
-					# See: https://forge.typo3.org/issues/42474
-					# Therefore it is held in the htmlAttributes array and the code removes this attribute if its value is set to 0.
-				htmlAttributesUsedByTheViewHelperDirectly {
-						# generic attributes
-					10 = class
-					20 = dir
-					30 = id
-					40 = lang
-					50 = style
-					60 = title
-					70 = accesskey
-					80 = tabindex
-					90 = onclick
-					100 = name
-					110 = value
-						# TextareaViewHelper
-					120 = autofocus
-					130 = rows
-					140 = cols
-					150 = placeholder
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.TEXTAREA.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 1
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 1
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Textblock.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Textblock.ts
deleted file mode 100644
index 805f39674b49a5d7e2e05e3331e60085995817f2..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Textblock.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			TEXTBLOCK {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/Textblock
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# TEXTBLOCK
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:format.raw
-				#
-				# @ToDo: add more details
-			TEXTBLOCK {
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.TEXTBLOCK.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 0
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 0
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Elements/Textline.ts b/typo3/sysext/form/Configuration/TypoScript/Elements/Textline.ts
deleted file mode 100644
index 0951d0eeebced7625bee34dd082ede53880cacc9..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Elements/Textline.ts
+++ /dev/null
@@ -1,160 +0,0 @@
-plugin.tx_form {
-		# elementPartials
-		# Used by: frontend, wizard (not implemented right now)
-		# Overwritable by user: FALSE
-		#
-		# Defines the template selection array for the form wizard.
-		# Each defined item is shown as option within the wizard.
-		#
-		# If there is no partialPath property in the userdefined TypoScript
-		# then elementPartials.ELEMENTNAME.10.partialPath is the default.
-	view {
-		elementPartials {
-			TEXTLINE {
-				10 {
-					displayName = Default
-					partialPath = FlatElements/Textfield
-				}
-			}
-		}
-	}
-
-	settings {
-		registeredElements {
-				# TEXTLINE
-				# Used by: frontend, wizard (not implemented right now)
-				# Used ViewHelper: f:form.textfield
-				#
-				# @ToDo: add more details
-			TEXTLINE {
-					# htmlAttributes
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# Defines allowed HTML attributes for a specific element.
-					# Based on selfhtml documentation version 8.1.2 (see http://wiki.selfhtml.org/wiki/Referenz:HTML/).
-					# This is needed to detect and map these strings within the user configured element definition as HTML attributes.
-					# As soon as prefix-* is defined every attribute is registered automatically as HTML attribute.
-				htmlAttributes {
-						# generic attributes
-					10 = id
-					20 = class
-					30 = accesskey
-					40 = contenteditable
-					50 = contextmenu
-					60 = dir
-					70 = draggable
-					80 = dropzone
-					90 = hidden
-					100 = lang
-					110 = spellcheck
-					120 = style
-					130 = tabindex
-					140 = title
-					150 = data-*
-					160 = translate
-						# element specific attributes
-					200 = type
-					210 = autocomplete
-					220 = autofocus
-					230 = disabled
-					240 = inputmode
-					250 = list
-					260 = maxlength
-					270 = minlength
-					280 = name
-					290 = pattern
-					300 = placeholder
-					310 = readonly
-					320 = required
-					330 = size
-					340 = value
-				}
-
-					# htmlAttributesUsedByTheViewHelperDirectly
-					# Used by: frontend
-					# Overwritable by user: FALSE
-					#
-					# Each HTML attribute defined at ".htmlAttributes" is available as array within the model.
-					# This array will be added to the resulting HTML tag.
-					# For this purpose the Fluid argument "additionalAttributes" of the ViewHelper is used.
-					#
-					# Some HTML attributes have to be assigned directly as an argument to the ViewHelper.
-					# The htmlAttributesUsedByTheViewHelperDirectly map is used to remove the specified
-					# HTML attribute from the "htmlAttributes" array and sets it for the model's "additionalArguments" array.
-					#
-					# There are two attributes which special behavior:
-					# 	* disabled
-					#	* readonly
-					# These attributes can be assigned to the most ViewHelpers but whenever a "disabled" attribute appears
-					# the browser will disable this element no matter of the value.
-					# See: https://forge.typo3.org/issues/42474
-					# Therefore it is held in the htmlAttributes array and the code removes this attribute if its value is set to 0.
-				htmlAttributesUsedByTheViewHelperDirectly {
-						# generic attributes
-					10 = class
-					20 = dir
-					30 = id
-					40 = lang
-					50 = style
-					60 = title
-					70 = accesskey
-					80 = tabindex
-					90 = onclick
-					100 = name
-					110 = value
-						# TextfieldViewHelper
-					120 = autofocus
-					130 = maxlength
-					140 = size
-					150 = placeholder
-					160 = pattern
-					170 = required
-					180 = type
-				}
-
-					# defaultHtmlAttributeValues
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: FALSE
-					#
-					# The following values are automatically set if there is no entry in the user configured element.
-				defaultHtmlAttributeValues {
-					type = text
-				}
-
-					# partialPath
-					# Used by: frontend, wizard (not implemented right now)
-					# Overwritable by user: TRUE
-					#
-					# The defined partial is used to render the element.
-					# The partial paths to the element are build based on the following rule:
-					# {$plugin.tx_form.view.partialRootPath}/{$themeName}/@actionName/{$partialPath}.
-				partialPath =< plugin.tx_form.view.elementPartials.TEXTLINE.10.partialPath
-
-					# visibleInShowAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the form.
-					# @ToDo: add more details
-				visibleInShowAction = 1
-
-					# visibleInConfirmationAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the confirmation page.
-					# @ToDo: add more details
-				visibleInConfirmationAction = 1
-
-					# visibleInProcessAction
-					# Used by: frontend
-					# Overwritable by user: TRUE
-					#
-					# If set to 1 this element is displayed in the mail.
-					# @ToDo: add more details
-				visibleInMail = 1
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Filters/Filters.ts b/typo3/sysext/form/Configuration/TypoScript/Filters/Filters.ts
deleted file mode 100644
index 6d6c36c44b2584af1f97861cf20e3d38c9b7e6cb..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Filters/Filters.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-plugin.tx_form {
-	settings {
-			# registeredFilters
-			# Used by: frontend, wizard (not implemented right now)
-			# Overwritable by user: FALSE
-			#
-			# The array holds all available filters.
-			# "displayName" is planned for the wizard (not implemented right now).
-		registeredFilters {
-			alphabetic {
-				displayName = Alphabetic
-				className = TYPO3\CMS\Form\Domain\Filter\AlphabeticFilter
-			}
-
-			alphanumeric {
-				displayName = Alphanumeric
-				className = TYPO3\CMS\Form\Domain\Filter\AlphanumericFilter
-			}
-
-			currency {
-				displayName = Currency
-				className = TYPO3\CMS\Form\Domain\Filter\CurrencyFilter
-			}
-
-			digit {
-				displayName = Digit
-				className = TYPO3\CMS\Form\Domain\Filter\DigitFilter
-			}
-
-			integer {
-				displayName = Integer
-				className = TYPO3\CMS\Form\Domain\Filter\IntegerFilter
-			}
-
-			lowercase {
-				displayName = Lowercase
-				className = TYPO3\CMS\Form\Domain\Filter\LowerCaseFilter
-			}
-
-			regexp {
-				displayName = Regular Expression
-				className = TYPO3\CMS\Form\Domain\Filter\RegExpFilter
-			}
-
-			stripnewlines {
-				displayName = Strip New Lines
-				className = TYPO3\CMS\Form\Domain\Filter\StripNewLinesFilter
-			}
-
-			titlecase {
-				displayName = Titlecase
-				className = TYPO3\CMS\Form\Domain\Filter\TitleCaseFilter
-			}
-
-			trim {
-				displayName = Trim
-				className = TYPO3\CMS\Form\Domain\Filter\TrimFilter
-			}
-
-			uppercase {
-				displayName = Uppercase
-				className = TYPO3\CMS\Form\Domain\Filter\UpperCaseFilter
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/Validators/Validators.ts b/typo3/sysext/form/Configuration/TypoScript/Validators/Validators.ts
deleted file mode 100644
index d8534f1558b971d0d6058bc85cacae345e08bf25..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/Validators/Validators.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-plugin.tx_form {
-	settings {
-			# registeredValidators
-			# Used by: frontend, wizard (not implemented right now)
-			# Overwritable by user: FALSE
-			#
-			# The array holds all available validators.
-			# "displayName" is planned for the form wizard (not implemented right now).
-		registeredValidators {
-			alphabetic {
-				displayName = Alphabetic
-				className = TYPO3\CMS\Form\Domain\Validator\AlphabeticValidator
-			}
-
-			alphanumeric {
-				displayName = Alphanumeric
-				className = TYPO3\CMS\Form\Domain\Validator\AlphanumericValidator
-			}
-
-			between {
-				displayName = Between
-				className = TYPO3\CMS\Form\Domain\Validator\BetweenValidator
-			}
-
-			date {
-				displayName = Date
-				className = TYPO3\CMS\Form\Domain\Validator\DateValidator
-			}
-
-			digit {
-				displayName = Digit
-				className = TYPO3\CMS\Form\Domain\Validator\DigitValidator
-			}
-
-			email {
-				displayName = Email address
-				className = TYPO3\CMS\Form\Domain\Validator\EmailValidator
-			}
-
-			equals {
-				displayName = Equals
-				className = TYPO3\CMS\Form\Domain\Validator\EqualsValidator
-			}
-
-			fileallowedtypes {
-				displayName = Allowed mimetypes for file
-				className = TYPO3\CMS\Form\Domain\Validator\FileAllowedTypesValidator
-			}
-
-			filemaximumsize {
-				displayName = Maximum size for file (bytes)
-				className = TYPO3\CMS\Form\Domain\Validator\FileMaximumSizeValidator
-			}
-
-			fileminimumsize {
-				displayName = Minimum size for file (bytes)
-				className = TYPO3\CMS\Form\Domain\Validator\FileMinimumSizeValidator
-			}
-
-			float {
-				displayName = Float
-				className = TYPO3\CMS\Form\Domain\Validator\FloatValidator
-			}
-
-			greaterthan {
-				displayName = Greater than
-				className = TYPO3\CMS\Form\Domain\Validator\GreaterThanValidator
-			}
-
-			inarray {
-				displayName = In array
-				className = TYPO3\CMS\Form\Domain\Validator\InArrayValidator
-			}
-
-			integer {
-				displayName = Integer
-				className = TYPO3\CMS\Form\Domain\Validator\IntegerValidator
-			}
-
-			ip {
-				displayName = Ip address
-				className = TYPO3\CMS\Form\Domain\Validator\IpValidator
-			}
-
-			length {
-				displayName = Length
-				className = TYPO3\CMS\Form\Domain\Validator\LengthValidator
-			}
-
-			lessthan {
-				displayName = Less than
-				className = TYPO3\CMS\Form\Domain\Validator\LessThanValidator
-			}
-
-			regexp {
-				displayName = Regular Expression
-				className = TYPO3\CMS\Form\Domain\Validator\RegExpValidator
-			}
-
-			required {
-				displayName = Required
-				className = TYPO3\CMS\Form\Domain\Validator\RequiredValidator
-			}
-
-			uri {
-				displayName = Uniform Resource Identifier
-				className = TYPO3\CMS\Form\Domain\Validator\UriValidator
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/backend.txt b/typo3/sysext/form/Configuration/TypoScript/backend.txt
new file mode 100644
index 0000000000000000000000000000000000000000..20604aa8aec75f5e3441cc3dbc53c96267315e74
--- /dev/null
+++ b/typo3/sysext/form/Configuration/TypoScript/backend.txt
@@ -0,0 +1,15 @@
+module.tx_form {
+    settings {
+        yamlConfigurations {
+            10 = EXT:form/Configuration/Yaml/BaseSetup.yaml
+            20 = EXT:form/Configuration/Yaml/FormEditorSetup.yaml
+            30 = EXT:form/Configuration/Yaml/FormEngineSetup.yaml
+        }
+    }
+
+    view {
+        templateRootPaths.10 = EXT:form/Resources/Private/Backend/Templates/
+        partialRootPaths.10 = EXT:form/Resources/Private/Backend/Partials/
+        layoutRootPaths.10 = EXT:form/Resources/Private/Backend/Layouts/
+    }
+}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/constants.txt b/typo3/sysext/form/Configuration/TypoScript/constants.txt
deleted file mode 100644
index 55c53277bd2386a0883486d93ed58707227797c3..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/TypoScript/constants.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-plugin.tx_form {
-	view {
-		# cat=plugin.tx_form/file; type=string; label=Path to template root (FE)
-		templateRootPath = EXT:form/Resources/Private/Templates/
-		# cat=plugin.tx_form/file; type=string; label=Path to template partials (FE)
-		partialRootPath = EXT:form/Resources/Private/Partials/
-		# cat=plugin.tx_form/file; type=string; label=Path to template layouts (FE)
-		layoutRootPath = EXT:form/Resources/Private/Layouts/
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/TypoScript/setup.txt b/typo3/sysext/form/Configuration/TypoScript/setup.txt
index acb530668a1175328ef05367579ad659e0270f20..172a79d81ffbee0baa2bdaeb637e863a5785aec6 100644
--- a/typo3/sysext/form/Configuration/TypoScript/setup.txt
+++ b/typo3/sysext/form/Configuration/TypoScript/setup.txt
@@ -1,256 +1,26 @@
-	# Replace rendering of old mailform
-tt_content.mailform >
-tt_content.mailform = COA
-tt_content.mailform.10 = < lib.stdheader
-tt_content.mailform.20 = FORM
-tt_content.mailform.20 {
-	stdWrap.wrap = <div class="csc-mailform">|</div>
-	stdWrap {
-		editIcons = tt_content: bodytext
-		editIcons.iconTitle.data = LLL:EXT:css_styled_content/pi1/locallang.xlf:eIcon.form
-		prefixComment = 2 | Mail form inserted:
-	}
-}
-
-	# Include model definition for all available form elements
-<INCLUDE_TYPOSCRIPT: source="DIR: EXT:form/Configuration/TypoScript/Elements" extensions="ts">
-	# Include definition of filters
-<INCLUDE_TYPOSCRIPT: source="DIR: EXT:form/Configuration/TypoScript/Filters" extensions="ts">
-	# Include definition of filters
-<INCLUDE_TYPOSCRIPT: source="DIR: EXT:form/Configuration/TypoScript/Validators" extensions="ts">
-
 plugin.tx_form {
-	features {
-		skipDefaultArguments = 1
-	}
-
-	view {
-		templateRootPaths {
-			10 = {$plugin.tx_form.view.templateRootPath}
-		}
-
-		partialRootPaths {
-			10 = {$plugin.tx_form.view.partialRootPath}
-		}
-
-		layoutRootPaths {
-			10 = {$plugin.tx_form.view.layoutRootPath}
-		}
-	}
-
-	_CSS_DEFAULT_STYLE (
-		div.csc-mailform ol {
-			list-style-type: none;
-		}
-
-		div.csc-mailform ol,
-		div.csc-mailform ol li {
-			margin: 0;
-			padding: 0;
-		}
-
-		div.csc-mailform ol li {
-			overflow: hidden;
-		}
-
-		div.csc-mailform fieldset {
-			margin: 0;
-			padding: 0;
-			position: relative;
-		}
-
-		div.csc-mailform legend {
-			margin-left: 1em;
-			color: #000000;
-			font-weight: bold;
-		}
-
-		div.csc-mailform fieldset ol {
-			padding: 1em 1em 0 1em;
-		}
-
-		div.csc-mailform fieldset li {
-			padding: 0.5em;
-			margin-bottom: 0.5em;
-			list-style: none;
-		}
-
-		div.csc-mailform fieldset.submit {
-			border-style: none;
-		}
-
-		/**
-		 * Normal label
-		 * Left aligned, in front of input
-		 */
-		div.csc-mailform li label {
-			float: left;
-			width: 13em;
-			margin-right: 1em;
-			vertical-align: baseline;
-		}
-
-		div.csc-mailform li input + label,
-		div.csc-mailform li textarea + label,
-		div.csc-mailform li select + label {
-			float: none;
-			width: auto;
-			margin-right: 0;
-			margin-left: 1em;
-		}
-
-		div.csc-mailform li textarea + label {
-			vertical-align: top;
-		}
-
-		label em,
-		legend em {
-			display: block;
-			color: #060;
-			font-size: 85%;
-			font-style: normal;
-			text-transform: uppercase;
-		}
-
-		legend em {
-			position: absolute;
-		}
-
-		label strong,
-		legend strong {
-			display: block;
-			color: #C00;
-			font-size: 85%;
-			font-weight: normal;
-			text-transform: uppercase;
-		}
-
-		legend strong {
-			position: absolute;
-			top: 1.4em;
-		}
-
-		/**
-		 * Labels alignment right
-		 */
-		.labels-alignment-right label,
-		.labels-alignment-right .fieldset-subgroup legend,
-		.labels-alignment-right.fieldset-subgroup legend {
-			text-align: right;
-		}
-
-		/**
-		 * Horizontal fieldset
-		 */
-		fieldset.fieldset-horizontal {
-			border-width: 0;
-		}
-
-		fieldset.fieldset-horizontal ol {
-			padding: 0;
-		}
-
-		fieldset.fieldset-horizontal li {
-			float: left;
-			padding: 0;
-			margin-right: 1em;
-		}
-
-		fieldset.fieldset-horizontal.label-below label {
-			display: block;
-			margin-left: 0;
-			margin-top: 0.2em;
-			font-size: 90%;
-			color: #999999;
-			text-align: left;
-		}
-
-		fieldset.fieldset-horizontal label em {
-			display: inline;
-		}
-
-		/**
-		 * Subgroup fieldset
-		 */
-		fieldset.fieldset-subgroup {
-			margin-bottom: -2em;
-			border-style: none;
-		}
-
-		fieldset.fieldset-subgroup legend {
-			margin-left: 0;
-			padding: 0;
-			font-weight: normal;
-			width: 13em;
-		}
-
-		fieldset.fieldset-subgroup ol {
-			position: relative;
-			top: -1.4em;
-			margin: 0 0 0 14em;
-			padding: 0;
-		}
-
-		fieldset.fieldset-subgroup li {
-			padding: 0;
-		}
-
-		fieldset.fieldset-subgroup input + label {
-			float: none;
-			width: auto;
-			display: inline;
-			margin: 0 0 0 1em;
-		}
-
-		/**
-		 * Labels as block
-		 * Labels displayed above or below the input fields
-		 */
-		.labels-block label {
-			display: block;
-			float: none;
-			margin: 0 0 0.5em;
-			width: auto;
-		}
-
-		.labels-block input + label,
-		.labels-block textarea + label {
-			margin: 0.5em 0 0;
-		}
-
-		.labels-block fieldset.fieldset-subgroup,
-		fieldset.labels-block.fieldset-subgroup {
-			margin-bottom: 0;
-		}
-
-		.labels-block .fieldset-subgroup legend,
-		.labels-block.fieldset-subgroup legend {
-			width: auto;
-		}
-
-		.labels-block .fieldset-subgroup legend em,
-		.labels-block.fieldset-subgroup legend em {
-			position: relative;
-		}
-
-		.labels-block .fieldset-subgroup legend strong,
-		.labels-block.fieldset-subgroup legend strong {
-			position: relative;
-			top: 0;
-		}
-
-		.labels-block .fieldset-subgroup ol,
-		.labels-block.fieldset-subgroup ol {
-			top: 0;
-			margin: 0;
-			padding: 0.5em 0 0;
-		}
-
-		/**
-		 * hide hidden elements
-		 */
-		.csc-form-element-hidden {
-			display: none;
-		}
-	)
+    view {
+        templateRootPaths.5 = EXT:form/Resources/Private/Frontend/Templates/
+        partialRootPaths.5 = EXT:form/Resources/Private/Frontend/Partials/
+        layoutRootPaths.5 = EXT:form/Resources/Private/Frontend/Layouts/
+    }
+
+    mvc {
+        callDefaultActionIfActionCantBeResolved = 1
+    }
+
+    settings {
+        yamlConfigurations {
+            10 = EXT:form/Configuration/Yaml/BaseSetup.yaml
+            20 = EXT:form/Configuration/Yaml/FormEngineSetup.yaml
+        }
+    }
 }
+
+# Rendering of content elements
+lib.tx_form.contentElementRendering = RECORDS
+lib.tx_form.contentElementRendering {
+    tables = tt_content
+    source.current = 1
+    dontCheckPid = 1
+}
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/UserTSconfig/userTSConfig.txt b/typo3/sysext/form/Configuration/UserTSconfig/userTSConfig.txt
deleted file mode 100644
index bb99a382ec2386c9d9473f6ce3df8b477f97ddb7..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Configuration/UserTSconfig/userTSConfig.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-# Enable the FORM wizard by default for all users
-setup.default.tx_form.showWizardByDefault = 1
diff --git a/typo3/sysext/form/Configuration/Yaml/BaseSetup.yaml b/typo3/sysext/form/Configuration/Yaml/BaseSetup.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..dacc84b9cffb4d9145ce0fc280aa57b2b0afd288
--- /dev/null
+++ b/typo3/sysext/form/Configuration/Yaml/BaseSetup.yaml
@@ -0,0 +1,340 @@
+TYPO3:
+  CMS:
+    Form:
+      persistenceManager:
+        allowedFileMounts:
+          10: 1:/user_upload/
+        allowSaveToExtensionPaths: false
+        #allowedExtensionPaths:
+          #10: EXT:example/Resources/Private/Forms/
+
+      prototypes:
+        standard:
+
+          ########### DEFAULT FORM ELEMENT DEFINITIONS ###########
+          formElementsDefinition:
+
+            ### BASE ELEMENTS ###
+            Form:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseFormElementMixin'
+              rendererClassName: 'TYPO3\CMS\Form\Domain\Renderer\FluidFormRenderer'
+              renderingOptions:
+                renderableNameInTemplate: 'form'
+                honeypot:
+                  enable: true
+                  formElementToUse: 'Honeypot'
+
+            ### FORM ELEMENTS: CONTAINER ###
+            Page:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseFormElementMixin'
+              implementationClassName: 'TYPO3\CMS\Form\Domain\Model\FormElements\Page'
+              renderingOptions:
+                renderableNameInTemplate: 'page'
+
+            SummaryPage:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.prototypes.standard.formElementsDefinition.Page'
+
+            Fieldset:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.FormElementMixin'
+              implementationClassName: 'TYPO3\CMS\Form\Domain\Model\FormElements\Section'
+              renderingOptions:
+                renderableNameInTemplate: 'section'
+
+            ### FORM ELEMENTS: INPUT ###
+            Text:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.TextMixin'
+
+            Password:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.TextMixin'
+
+            AdvancedPassword:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.prototypes.standard.formElementsDefinition.Password'
+              implementationClassName: 'TYPO3\CMS\Form\Domain\Model\FormElements\AdvancedPassword'
+              properties:
+                elementClassAttribute: 'input-medium'
+                confirmationLabel: ''
+                # Optional description (hint) for the first password input element
+                #passwordDescription: ''
+                confirmationClassAttribute: 'input-medium'
+
+            Textarea:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.TextMixin'
+              properties:
+                elementClassAttribute: 'xxlarge'
+
+            Honeypot:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.TextMixin'
+              properties:
+                renderAsHiddenField: false
+                styleAttribute: 'position:absolute; margin:0 0 0 -999em;'
+
+            ### FORM ELEMENTS: SELECT ###
+            Checkbox:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.FormElementMixin'
+              properties:
+                elementClassAttribute: 'add-on'
+                value: 1
+
+            MultiCheckbox:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.MultiSelectionMixin'
+
+            MultiSelect:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.MultiSelectionMixin'
+              properties:
+                elementClassAttribute: 'xlarge'
+
+            RadioButton:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.SingleSelectionMixin'
+              properties:
+                elementClassAttribute: 'xlarge'
+
+            SingleSelect:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.SingleSelectionMixin'
+
+            ### FORM ELEMENTS: CUSTOM ###
+            DatePicker:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.FormElementMixin'
+              implementationClassName: 'TYPO3\CMS\Form\Domain\Model\FormElements\DatePicker'
+              properties:
+                elementClassAttribute: 'small'
+                timeSelectorClassAttribute: 'mini'
+                dateFormat: 'Y-m-d'
+                enableDatePicker: true
+                displayTimeSelector: false
+
+            StaticText:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.ReadOnlyFormElementMixin'
+              properties:
+                text: ''
+
+            Hidden:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.FormElementMixin'
+
+            ContentElement:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.ReadOnlyFormElementMixin'
+              properties:
+                contentElementUid: ''
+
+            ### FORM ELEMENTS: UPLOADS ###
+            FileUpload:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.FileUploadMixin'
+              properties:
+                allowedMimeTypes: ['application/doc', 'application/docx', 'application/odt', 'application/pdf']
+
+            ImageUpload:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.FileUploadMixin'
+              properties:
+                allowedMimeTypes: ['image/jpeg', 'image/png', 'image/bmp']
+                elementClassAttribute: 'lightbox'
+                imageLinkMaxWidth: 500
+                imageMaxWidth: 500
+                imageMaxHeight: 500
+
+          ### FINISHERS ###
+
+          finishersDefinition:
+            Closure:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.finishersTranslationSettingsMixin'
+              implementationClassName: 'TYPO3\CMS\Form\Domain\Finishers\ClosureFinisher'
+              options:
+                #closure:
+
+            Confirmation:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.finishersTranslationSettingsMixin'
+              implementationClassName: 'TYPO3\CMS\Form\Domain\Finishers\ConfirmationFinisher'
+              #options:
+                #message: ''
+
+            EmailToSender:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.finishersEmailMixin'
+
+            EmailToReceiver:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.finishersEmailMixin'
+
+            DeleteUploads:
+              implementationClassName: 'TYPO3\CMS\Form\Domain\Finishers\DeleteUploadsFinisher'
+
+            FlashMessage:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.finishersTranslationSettingsMixin'
+              implementationClassName: 'TYPO3\CMS\Form\Domain\Finishers\FlashMessageFinisher'
+              #options:
+                #messageBody: ''
+                #messageTitle: ''
+                #messageArguments: {}
+                #messageCode: 0
+                #severity: 0
+
+            Redirect:
+              implementationClassName: 'TYPO3\CMS\Form\Domain\Finishers\RedirectFinisher'
+              #options:
+                #pageUid: 1
+                #additionalParameters: ''
+                #delay: 0
+                #statusCode: 303
+
+            SaveToDatabase:
+              implementationClassName: 'TYPO3\CMS\Form\Domain\Finishers\SaveToDatabaseFinisher'
+              #options:
+                #table: ''
+                #elements:
+                #  <elementIdentifier>:
+                #    mapOnDatabaseColumn: sender_name
+                #    saveFileIdentifierInsteadOfUid: 'false'
+
+          ### VALIDATORS ###
+          validatorsDefinition:
+            NotEmpty:
+              implementationClassName: 'TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator'
+            DateTime:
+              implementationClassName: 'TYPO3\CMS\Extbase\Validation\Validator\DateTimeValidator'
+            Alphanumeric:
+              implementationClassName: 'TYPO3\CMS\Extbase\Validation\Validator\AlphanumericValidator'
+            Text:
+              implementationClassName: 'TYPO3\CMS\Extbase\Validation\Validator\TextValidator'
+            StringLength:
+              implementationClassName: 'TYPO3\CMS\Extbase\Validation\Validator\StringLengthValidator'
+              #options:
+                #minimum: 0
+                #maximum: 0
+            EmailAddress:
+              implementationClassName: 'TYPO3\CMS\Extbase\Validation\Validator\EmailAddressValidator'
+            Integer:
+              implementationClassName: 'TYPO3\CMS\Extbase\Validation\Validator\IntegerValidator'
+            Float:
+              implementationClassName: 'TYPO3\CMS\Extbase\Validation\Validator\FloatValidator'
+            NumberRange:
+              implementationClassName: 'TYPO3\CMS\Extbase\Validation\Validator\NumberRangeValidator'
+              #options:
+                #minimum: 0
+                #maximum: 0
+            RegularExpression:
+              implementationClassName: 'TYPO3\CMS\Extbase\Validation\Validator\RegularExpressionValidator'
+              #options:
+                #regularExpression: '/^.*$/'
+            Count:
+              implementationClassName: 'TYPO3\CMS\Form\Mvc\Validation\CountValidator'
+              #options:
+                #minimum: 0
+                #maximum: 0
+
+      ########### MIXINS ###########
+      mixins:
+        translationSettingsMixin:
+          translation:
+            translationFile: 'EXT:form/Resources/Private/Language/locallang.xlf'
+            translatePropertyValueIfEmpty: true
+
+        finishersTranslationSettingsMixin:
+          options:
+            __inheritances:
+              10: 'TYPO3.CMS.Form.mixins.translationSettingsMixin'
+
+        ########### FORM ELEMENT MIXINS ###########
+        formElementMixins:
+          BaseFormElementMixin:
+            renderingOptions:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.translationSettingsMixin'
+
+              templateRootPaths:
+                10: 'EXT:form/Resources/Private/Frontend/Templates/FormElements/'
+              partialRootPaths:
+                10: 'EXT:form/Resources/Private/Frontend/Partials/FormElements/'
+              layoutRootPaths:
+                10: 'EXT:form/Resources/Private/Frontend/Layouts/FormElements/'
+
+              # It is possible to set a full path to a template e.g. for custom elements
+              # In this case 'templateRootPaths' will be ignored
+              # templatePathAndFilename: 'EXT:form/Resources/Private/Frontend/Templates/FormElements/RadioButton.html'
+
+              # set this to TRUE if you want to avoid exceptions for FormElements without definitions
+              skipUnknownElements: true
+
+          ReadOnlyFormElementMixin:
+            __inheritances:
+              10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseFormElementMixin'
+            implementationClassName: 'TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement'
+            renderingOptions:
+              renderableNameInTemplate: 'element'
+
+          FormElementMixin:
+            __inheritances:
+              10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseFormElementMixin'
+            implementationClassName: 'TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement'
+            properties:
+              containerClassAttribute: 'input'
+              elementClassAttribute: ''
+              elementErrorClassAttribute: 'error'
+            renderingOptions:
+              renderableNameInTemplate: 'element'
+
+          TextMixin:
+            __inheritances:
+              10: 'TYPO3.CMS.Form.mixins.formElementMixins.FormElementMixin'
+
+          SelectionMixin:
+            __inheritances:
+              10: 'TYPO3.CMS.Form.mixins.formElementMixins.FormElementMixin'
+
+          SingleSelectionMixin:
+            __inheritances:
+              10: 'TYPO3.CMS.Form.mixins.formElementMixins.SelectionMixin'
+
+          MultiSelectionMixin:
+            __inheritances:
+              10: 'TYPO3.CMS.Form.mixins.formElementMixins.SelectionMixin'
+
+          FileUploadMixin:
+            __inheritances:
+              10: 'TYPO3.CMS.Form.mixins.formElementMixins.FormElementMixin'
+            implementationClassName: 'TYPO3\CMS\Form\Domain\Model\FormElements\FileUpload'
+            properties:
+              saveToFileMount: '1:/user_upload/'
+
+        finishersEmailMixin:
+          __inheritances:
+            10: 'TYPO3.CMS.Form.mixins.finishersTranslationSettingsMixin'
+          implementationClassName: 'TYPO3\CMS\Form\Domain\Finishers\EmailFinisher'
+          options:
+            #subject: ''
+            #recipientAddress: ''
+            #recipientName: ''
+            #senderAddress:
+            #senderName: ''
+            #replyToAddress: ''
+            #carbonCopyAddress: ''
+            #blindCarbonCopyAddress: ''
+            #format: 'html'
+            #attachUploads: true
+            #translation:
+            #  language: 'default'
+            # {@format} depends the 'format' value
+            templatePathAndFilename: 'EXT:form/Resources/Private/Frontend/Templates/Finishers/Email/{@format}.html'
+            #partialRootPaths: []
+            #layoutRootPaths: []
+            #variables: {}
diff --git a/typo3/sysext/form/Configuration/Yaml/FormEditorSetup.yaml b/typo3/sysext/form/Configuration/Yaml/FormEditorSetup.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..98edc7625355a6040c9d78685d3c0f800f75164c
--- /dev/null
+++ b/typo3/sysext/form/Configuration/Yaml/FormEditorSetup.yaml
@@ -0,0 +1,1005 @@
+TYPO3:
+  CMS:
+    Form:
+      ########### FORM MANAGER CONFIGURATION ###########
+      formManager:
+        dynamicRequireJsModules:
+          app: 'TYPO3/CMS/Form/Backend/FormManager'
+          viewModel: 'TYPO3/CMS/Form/Backend/FormManager/ViewModel'
+        stylesheets:
+          100: 'EXT:form/Resources/Public/Css/form.css'
+        translationFile: 'EXT:form/Resources/Private/Language/Database.xlf'
+        javaScriptTranslationFile: 'EXT:form/Resources/Private/Language/locallang_formManager_javascript.xlf'
+        selectablePrototypesConfiguration:
+          100:
+            identifier: 'standard'
+            label: 'formManager.selectablePrototypesConfiguration.standard.label'
+            newFormTemplates:
+              100:
+                templatePath: 'EXT:form/Resources/Private/Backend/Templates/FormEditor/Yaml/NewForms/BlankForm.yaml'
+                label: 'formManager.selectablePrototypesConfiguration.standard.newFormTemplates.blankForm.label'
+              200:
+                templatePath: 'EXT:form/Resources/Private/Backend/Templates/FormEditor/Yaml/NewForms/SimpleContactForm.yaml'
+                label: 'formManager.selectablePrototypesConfiguration.standard.newFormTemplates.simpleContactForm.label'
+        controller:
+          deleteAction:
+            errorTitle: 'formManagerController.deleteAction.error.title'
+            errorMessage: 'formManagerController.deleteAction.error.body'
+
+      ########### FORMEDITOR CONFIGURATION ###########
+      prototypes:
+        standard:
+          formEditor:
+            translationFile: 'EXT:form/Resources/Private/Language/Database.xlf'
+            dynamicRequireJsModules:
+              app: 'TYPO3/CMS/Form/Backend/FormEditor'
+              mediator: 'TYPO3/CMS/Form/Backend/FormEditor/Mediator'
+              viewModel: 'TYPO3/CMS/Form/Backend/FormEditor/ViewModel'
+              additionalViewModelModules:
+
+            addInlineSettings: []
+            maximumUndoSteps: 10
+
+            stylesheets:
+              # @toDo: move form.less to the TYPO3 Build folder
+              200: 'EXT:form/Resources/Public/Css/form.css'
+
+            formEditorTemplates:
+              templateRootPaths:
+                10: 'EXT:form/Resources/Private/Backend/Templates/FormEditor/'
+              partialRootPaths:
+                10: 'EXT:form/Resources/Private/Backend/Partials/FormEditor/'
+              layoutRootPaths:
+                10: 'EXT:form/Resources/Private/Backend/Layouts/FormEditor/'
+
+              # Element options editors
+              FormElement-_ElementToolbar: 'Stage/_ElementToolbar'
+              FormElement-_UnknownElement: 'Stage/_UnknownElement'
+              FormElement-Page: 'Stage/Page'
+              FormElement-SummaryPage: 'Stage/SummaryPage'
+              FormElement-Fieldset: 'Stage/Fieldset'
+              FormElement-Text: 'Stage/Text'
+              FormElement-Password: 'Stage/Password'
+              FormElement-AdvancedPassword: 'Stage/AdvancedPassword'
+              FormElement-Textarea: 'Stage/Textarea'
+              FormElement-Checkbox: 'Stage/Checkbox'
+              FormElement-MultiCheckbox: 'Stage/MultiCheckbox'
+              FormElement-MultiSelect: 'Stage/MultiSelect'
+              FormElement-RadioButton: 'Stage/RadioButton'
+              FormElement-SingleSelect: 'Stage/SingleSelect'
+              FormElement-DatePicker: 'Stage/DatePicker'
+              FormElement-StaticText: 'Stage/StaticText'
+              FormElement-Hidden: 'Stage/Hidden'
+              FormElement-ContentElement: 'Stage/ContentElement'
+              FormElement-FileUpload: 'Stage/FileUpload'
+              FormElement-ImageUpload: 'Stage/ImageUpload'
+
+              Modal-InsertElements: 'Modals/InsertElements'
+              Modal-InsertPages: 'Modals/InsertPages'
+              Modal-ValidationErrors: 'Modals/ValidationErrors'
+
+              Inspector-FormElementHeaderEditor: 'Inspector/FormElementHeaderEditor'
+              Inspector-CollectionElementHeaderEditor: 'Inspector/CollectionElementHeaderEditor'
+              Inspector-TextEditor: 'Inspector/TextEditor'
+              Inspector-PropertyGridEditor: 'Inspector/PropertyGridEditor'
+              Inspector-SingleSelectEditor: 'Inspector/SingleSelectEditor'
+              Inspector-TextareaEditor: 'Inspector/TextareaEditor'
+              Inspector-RemoveElementEditor: 'Inspector/RemoveElementEditor'
+              Inspector-FinishersEditor: 'Inspector/FinishersEditor'
+              Inspector-ValidatorsEditor: 'Inspector/ValidatorsEditor'
+              Inspector-RequiredValidatorEditor: 'Inspector/RequiredValidatorEditor'
+              Inspector-CheckboxEditor: 'Inspector/CheckboxEditor'
+              Inspector-Typo3WinBrowserEditor: 'Inspector/Typo3WinBrowserEditor'
+
+            formElementPropertyValidatorsDefinition:
+              NotEmpty:
+                errorMessage: 'formEditor.formElementPropertyValidatorsDefinition.NotEmpty.label'
+              Integer:
+                errorMessage: 'formEditor.formElementPropertyValidatorsDefinition.Integer.label'
+              NaiveEmail:
+                errorMessage: 'formEditor.formElementPropertyValidatorsDefinition.NaiveEmail.label'
+              NaiveEmailOrEmpty:
+                errorMessage: 'formEditor.formElementPropertyValidatorsDefinition.NaiveEmail.label'
+              FormElementIdentifierWithinCurlyBracesInclusive:
+                errorMessage: 'formEditor.formElementPropertyValidatorsDefinition.FormElementIdentifierWithinCurlyBraces.label'
+              FormElementIdentifierWithinCurlyBracesExclusive:
+                errorMessage: 'formEditor.formElementPropertyValidatorsDefinition.FormElementIdentifierWithinCurlyBraces.label'
+
+            formElementGroups:
+              input:
+                label: 'formEditor.formElementGroups.input.label'
+              select:
+                label: 'formEditor.formElementGroups.select.label'
+              custom:
+                label: 'formEditor.formElementGroups.custom.label'
+              container:
+                label: 'formEditor.formElementGroups.container.label'
+              page:
+                label: 'formEditor.formElementGroups.page.label'
+
+          ########### DEFAULT FORM ELEMENT DEFINITIONS ###########
+          formElementsDefinition:
+            Form:
+              formEditor:
+                _isCompositeFormElement: false
+                _isTopLevelFormElement: true
+
+                saveSuccessFlashMessageTitle: 'formEditor.elements.Form.saveSuccessFlashMessageTitle'
+                saveSuccessFlashMessageMessage: 'formEditor.elements.Form.saveSuccessFlashMessageMessage'
+
+                modalValidationErrorsDialogTitle: 'formEditor.modals.validationErrors.dialogTitle'
+                modalValidationErrorsConfirmButton: 'formEditor.modals.validationErrors.confirmButton'
+
+                modalInsertElementsDialogTitle: 'formEditor.modals.insertElements.dialogTitle'
+                modalInsertPagesDialogTitle: 'formEditor.modals.newPages.dialogTitle'
+
+                modalCloseDialogMessage: 'formEditor.modals.close.dialogMessage'
+                modalCloseDialogTitle: 'formEditor.modals.close.dialogTitle'
+                modalCloseConfirmButton: 'formEditor.modals.close.confirmButton'
+                modalCloseCancleButton: 'formEditor.modals.close.cancleButton'
+
+                modalRemoveElementDialogTitle: 'formEditor.modals.removeElement.dialogTitle'
+                modalRemoveElementDialogMessage: 'formEditor.modals.removeElement.dialogMessage'
+                modalRemoveElementConfirmButton: 'formEditor.modals.removeElement.confirmButton'
+                modalRemoveElementCancleButton: 'formEditor.modals.removeElement.cancleButton'
+                modalRemoveElementLastAvailablePageFlashMessageTitle: 'formEditor.modals.removeElement.lastAvailablePageFlashMessageTitle'
+                modalRemoveElementLastAvailablePageFlashMessageMessage: 'formEditor.modals.removeElement.lastAvailablePageFlashMessageMessage'
+
+                paginationTitle: 'formEditor.pagination.title'
+
+                iconIdentifier: 'content-elements-mailform'
+                predefinedDefaults:
+                editors:
+                  900:
+                    identifier: 'finishers'
+                    templateName: 'Inspector-FinishersEditor'
+                    label: 'formEditor.elements.Form.editor.finishers.label'
+                    selectOptions:
+                      10:
+                        value: ''
+                        label: 'formEditor.elements.Form.editor.finishers.EmptyValue.label'
+                      20:
+                        value: 'EmailToSender'
+                        label: 'formEditor.elements.Form.editor.finishers.EmailToSender.label'
+                      30:
+                        value: 'EmailToReceiver'
+                        label: 'formEditor.elements.Form.editor.finishers.EmailToReceiver.label'
+                      40:
+                        value: 'Redirect'
+                        label: 'formEditor.elements.Form.editor.finishers.Redirect.label'
+                      50:
+                        value: 'DeleteUploads'
+                        label: 'formEditor.elements.Form.editor.finishers.DeleteUploads.label'
+
+                propertyCollections:
+                  finishers:
+                    10:
+                      __inheritances:
+                        10: 'TYPO3.CMS.Form.mixins.formElementMixins.formEmailFinisherMixin'
+                      identifier: 'EmailToSender'
+
+                    20:
+                      __inheritances:
+                        10: 'TYPO3.CMS.Form.mixins.formElementMixins.formEmailFinisherMixin'
+                      identifier: 'EmailToReceiver'
+                      editors:
+                        100:
+                          label: 'formEditor.elements.Form.finisher.EmailToReceiver.editor.header.label'
+                        200:
+                          label: 'formEditor.elements.Form.finisher.EmailToReceiver.editor.subject.label'
+                        300:
+                          label: 'formEditor.elements.Form.finisher.EmailToReceiver.editor.recipientAddress.label'
+                        400:
+                          label: 'formEditor.elements.Form.finisher.EmailToReceiver.editor.recipientName.label'
+                        500:
+                          label: 'formEditor.elements.Form.finisher.EmailToReceiver.editor.senderAddress.label'
+                        600:
+                          label: 'formEditor.elements.Form.finisher.EmailToReceiver.editor.senderName.label'
+                        700:
+                          label: 'formEditor.elements.Form.finisher.EmailToReceiver.editor.replyToAddress.label'
+                        800:
+                          label: 'formEditor.elements.Form.finisher.EmailToReceiver.editor.carbonCopyAddress.label'
+                        900:
+                          label: 'formEditor.elements.Form.finisher.EmailToReceiver.editor.blindCarbonCopyAddress.label'
+                        1000:
+                          label: 'formEditor.elements.Form.finisher.EmailToReceiver.editor.format.label'
+                        1100:
+                          label: 'formEditor.elements.Form.finisher.EmailToReceiver.editor.attachUploads.label'
+                        1200:
+                          identifier: 'language'
+                          templateName: 'Inspector-SingleSelectEditor'
+                          label: 'formEditor.elements.Form.finisher.EmailToReceiver.editor.language.label'
+                          propertyPath: 'options.translation.language'
+                          selectOptions:
+                            10:
+                              value: 'default'
+                              label: 'formEditor.elements.Form.finisher.EmailToReceiver.editor.language.1'
+
+                    30:
+                      identifier: 'Redirect'
+                      editors:
+                        __inheritances:
+                          10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                        100:
+                          label: 'formEditor.elements.Form.finisher.Redirect.editor.header.label'
+                        200:
+                          identifier: 'pageUid'
+                          templateName: 'Inspector-Typo3WinBrowserEditor'
+                          label: 'formEditor.elements.Form.finisher.Redirect.editor.pageUid.label'
+                          buttonLabel: 'formEditor.elements.Form.finisher.Redirect.editor.pageUid.buttonLabel'
+                          browsableType: pages
+                          propertyPath: 'options.pageUid'
+                          propertyValidatorsMode: 'OR'
+                          propertyValidators:
+                            10: 'Integer'
+                            20: 'FormElementIdentifierWithinCurlyBracesExclusive'
+
+                        300:
+                          identifier: 'additionalParameters'
+                          templateName: 'Inspector-TextEditor'
+                          label: 'formEditor.elements.Form.finisher.Redirect.editor.additionalParameters.label'
+                          propertyPath: 'options.additionalParameters'
+
+                    40:
+                      identifier: 'DeleteUploads'
+                      editors:
+                        __inheritances:
+                          10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                        100:
+                          label: 'formEditor.elements.Form.finisher.DeleteUploads.editor.header.label'
+
+                    50:
+                      identifier: 'Confirmation'
+                      editors:
+                        __inheritances:
+                          10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                        100:
+                          label: 'formEditor.elements.Form.finisher.Confirmation.editor.header.label'
+
+                    60:
+                      identifier: 'Closure'
+                      editors:
+                        __inheritances:
+                          10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                        100:
+                          label: 'formEditor.elements.Form.finisher.Closure.editor.header.label'
+
+                    70:
+                      identifier: 'FlashMessage'
+                      editors:
+                        __inheritances:
+                          10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                        100:
+                          label: 'formEditor.elements.Form.finisher.FlashMessage.editor.header.label'
+
+                    80:
+                      identifier: 'SaveToDatabase'
+                      editors:
+                        __inheritances:
+                          10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                        100:
+                          label: 'formEditor.elements.Form.finisher.SaveToDatabase.editor.header.label'
+
+            ### FORM ELEMENTS: CONTAINER ###
+            Fieldset:
+              formEditor:
+                label: 'formEditor.elements.Fieldset.label'
+                group: container
+                groupSorting: 100
+                _isCompositeFormElement: true
+                iconIdentifier: 't3-form-icon-fieldset'
+                editors:
+                  200:
+                    label: 'formEditor.elements.Fieldset.editor.label.label'
+                  800: null
+
+            ### FORM ELEMENTS: PAGE TYPES ###
+            Page:
+              formEditor:
+                __inheritances:
+                  10: 'TYPO3.CMS.Form.mixins.formElementMixins.RemovableFormElementMixin'
+                predefinedDefaults:
+                label: 'formEditor.elements.Page.label'
+                group: page
+                groupSorting: 100
+                _isTopLevelFormElement: true
+                _isCompositeFormElement: true
+                iconIdentifier: 't3-form-icon-page'
+                editors:
+                  200:
+                    label: 'formEditor.elements.Page.editor.label.label'
+
+            SummaryPage:
+              formEditor:
+                predefinedDefaults:
+                label: 'formEditor.elements.SummaryPage.label'
+                group: page
+                groupSorting: 200
+                _isTopLevelFormElement: true
+                _isCompositeFormElement: false
+                iconIdentifier: 't3-form-icon-summary-page'
+                editors:
+                  200:
+                    label: 'formEditor.elements.SummaryPage.editor.label.label'
+
+            ### FORM ELEMENTS: INPUT ###
+
+            Text:
+              formEditor:
+                label: 'formEditor.elements.Text.label'
+                group: input
+                groupSorting: 100
+                iconIdentifier: 't3-form-icon-text'
+
+            Password:
+              formEditor:
+                label: 'formEditor.elements.Password.label'
+                group: input
+                groupSorting: 300
+                iconIdentifier: 't3-form-icon-password'
+
+            AdvancedPassword:
+              formEditor:
+                label: 'formEditor.elements.AdvancedPassword.label'
+                group: input
+                groupSorting: 400
+                predefinedDefaults:
+                  properties:
+                    confirmationLabel: 'formEditor.element.AdvancedPassword.editor.confirmationLabel.predefinedDefaults'
+                  defaultValue: null
+                iconIdentifier: 't3-form-icon-advanced-password'
+                editors:
+                  300:
+                    identifier: 'confirmationLabel'
+                    templateName: 'Inspector-TextEditor'
+                    label: 'formEditor.elements.AdvancedPassword.editor.confirmationLabel.label'
+                    propertyPath: 'properties.confirmationLabel'
+                  500: null
+
+            Textarea:
+              formEditor:
+                label: 'formEditor.elements.Textarea.label'
+                group: input
+                groupSorting: 200
+                iconIdentifier: 't3-form-icon-textarea'
+
+            ### FORM ELEMENTS: SELECT ###
+            Checkbox:
+              formEditor:
+                label: 'formEditor.elements.Checkbox.label'
+                group: select
+                groupSorting: 100
+                iconIdentifier: 't3-form-icon-checkbox'
+
+            MultiCheckbox:
+              formEditor:
+                label: 'formEditor.elements.MultiCheckbox.label'
+                group: select
+                groupSorting: 500
+                iconIdentifier: 't3-form-icon-multi-checkbox'
+
+            MultiSelect:
+              formEditor:
+                label: 'formEditor.elements.MultiSelect.label'
+                group: select
+                groupSorting: 400
+                iconIdentifier: 't3-form-icon-multi-select'
+
+            RadioButton:
+              formEditor:
+                label: 'formEditor.elements.RadioButton.label'
+                group: select
+                groupSorting: 300
+                iconIdentifier: 't3-form-icon-radio-button'
+
+            SingleSelect:
+              formEditor:
+                label: 'formEditor.elements.SingleSelect.label'
+                group: select
+                groupSorting: 200
+                iconIdentifier: 't3-form-icon-single-select'
+
+            ### FORM ELEMENTS: CUSTOM ###
+            DatePicker:
+              formEditor:
+                label: 'formEditor.elements.DatePicker.label'
+                group: custom
+                groupSorting: 100
+                iconIdentifier: 't3-form-icon-date-picker'
+                editors:
+                  900:
+                    identifier: 'validators'
+                    templateName: 'Inspector-ValidatorsEditor'
+                    label: 'formEditor.elements.DatePicker.editor.validators.label'
+                    selectOptions:
+                      10:
+                        value: ''
+                        label: 'formEditor.elements.DatePicker.editor.validators.EmptyValue.label'
+                      20:
+                        value: 'DateTime'
+                        label: 'formEditor.elements.DatePicker.editor.validators.DateTime.label'
+
+                propertyCollections:
+                  validators:
+                    10:
+                      identifier: 'DateTime'
+                      editors:
+                        __inheritances:
+                          10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                        100:
+                          label: 'formEditor.elements.DatePicker.validators.DateTime.editor.header.label'
+
+            StaticText:
+              formEditor:
+                label: 'formEditor.elements.StaticText.label'
+                group: custom
+                groupSorting: 400
+                predefinedDefaults:
+                  properties:
+                    text: ''
+                iconIdentifier: 't3-form-icon-static-text'
+                editors:
+                  300:
+                    identifier: 'staticText'
+                    templateName: 'Inspector-TextareaEditor'
+                    label: 'formEditor.elements.StaticText.editor.staticText.label'
+                    propertyPath: 'properties.text'
+
+            ContentElement:
+              formEditor:
+                label: 'formEditor.elements.ContentElement.label'
+                group: custom
+                groupSorting: 500
+                predefinedDefaults:
+                  properties:
+                    contentElementUid: ''
+                iconIdentifier: 't3-form-icon-content-element'
+                editors:
+                  200: null
+                  300:
+                    identifier: 'staticText'
+                    templateName: 'Inspector-Typo3WinBrowserEditor'
+                    label: 'formEditor.elements.StaticText.editor.contentElement.label'
+                    buttonLabel: 'formEditor.elements.StaticText.editor.contentElement.buttonLabel'
+                    browsableType: tt_content
+                    propertyPath: 'properties.contentElementUid'
+                    propertyValidatorsMode: 'OR'
+                    propertyValidators:
+                      10: 'Integer'
+                      20: 'FormElementIdentifierWithinCurlyBracesExclusive'
+
+            ### FORM ELEMENTS: UPLOADS ###
+            FileUpload:
+              formEditor:
+                label: 'formEditor.elements.FileUpload.label'
+                group: custom
+                groupSorting: 200
+                predefinedDefaults:
+                  properties:
+                    allowedMimeTypes: ['application/doc', 'application/docx', 'application/odt', 'application/pdf']
+                iconIdentifier: 't3-form-icon-file-upload'
+                editors:
+                  300:
+                    identifier: 'allowedMimeTypes'
+                    templateName: 'Inspector-SingleSelectEditor'
+                    label: 'formEditor.elements.FileUpload.editor.allowedMimeTypes.label'
+                    propertyPath: 'properties.allowedMimeTypes'
+                    selectOptions:
+                      10:
+                        value: ['application/doc', 'application/docx', 'application/odt', 'application/pdf']
+                        label: 'formEditor.elements.FileUpload.editor.allowedMimeTypes.1'
+                      20:
+                        value: ['application/xls']
+                        label: 'formEditor.elements.FileUpload.editor.allowedMimeTypes.2'
+
+            ImageUpload:
+              formEditor:
+                label: 'formEditor.elements.ImageUpload.label'
+                group: custom
+                groupSorting: 300
+                predefinedDefaults:
+                  properties:
+                    allowedMimeTypes: ['image/jpeg', 'image/png', 'image/bmp']
+                iconIdentifier: 't3-form-icon-image-upload'
+
+          ### FINISHERS ###
+          finishersDefinition:
+            EmailToSender:
+              formEditor:
+                iconIdentifier: 't3-form-icon-finisher'
+                label: 'formEditor.elements.Form.finisher.EmailToSender.editor.header.label'
+                predefinedDefaults:
+                  options:
+                    subject: ''
+                    recipientAddress: ''
+                    recipientName: ''
+                    senderAddress: ''
+                    senderName: ''
+                    replyToAddress: ''
+                    carbonCopyAddress: ''
+                    blindCarbonCopyAddress: ''
+                    format: 'html'
+                    attachUploads: true
+
+            EmailToReceiver:
+              formEditor:
+                iconIdentifier: 't3-form-icon-finisher'
+                label: 'formEditor.elements.Form.finisher.EmailToReceiver.editor.header.label'
+                predefinedDefaults:
+                  options:
+                    subject: ''
+                    recipientAddress: ''
+                    recipientName: ''
+                    senderAddress: ''
+                    senderName: ''
+                    replyToAddress: ''
+                    carbonCopyAddress: ''
+                    blindCarbonCopyAddress: ''
+                    format: 'html'
+                    attachUploads: true
+                    translation:
+                      language: ''
+
+            Redirect:
+              formEditor:
+                iconIdentifier: 't3-form-icon-finisher'
+                label: 'formEditor.elements.Form.finisher.Redirect.editor.header.label'
+                predefinedDefaults:
+                  options:
+                    pageUid: ''
+                    additionalParameters: ''
+
+            Closure:
+              formEditor:
+                iconIdentifier: 't3-form-icon-finisher'
+                label: 'formEditor.elements.Form.finisher.Closure.editor.header.label'
+                predefinedDefaults:
+                  options:
+                    closure: ''
+
+            Confirmation:
+              formEditor:
+                iconIdentifier: 't3-form-icon-finisher'
+                label: 'formEditor.elements.Form.finisher.Confirmation.editor.header.label'
+                predefinedDefaults:
+                  options:
+                    message: ''
+
+            FlashMessage:
+              formEditor:
+                iconIdentifier: 't3-form-icon-finisher'
+                label: 'formEditor.elements.Form.finisher.FlashMessage.editor.header.label'
+                predefinedDefaults:
+                  options:
+                    messageBody: ''
+                    messageTitle: ''
+                    messageArguments: ''
+                    messageCode: 0
+                    severity: 0
+
+            SaveToDatabase:
+              formEditor:
+                iconIdentifier: 't3-form-icon-finisher'
+                label: 'formEditor.elements.Form.finisher.SaveToDatabase.editor.header.label'
+                predefinedDefaults:
+                  options:
+                    table: ''
+                    elements:
+
+            DeleteUploads:
+              formEditor:
+                iconIdentifier: 't3-form-icon-finisher'
+                label: 'formEditor.elements.Form.finisher.DeleteUploads.editor.header.label'
+
+          ### VALIDATORS ###
+          validatorsDefinition:
+            NotEmpty:
+              formEditor:
+                iconIdentifier: 't3-form-icon-validator'
+                label : 'formEditor.elements.FormElement.editor.requiredValidator.label'
+            DateTime:
+              formEditor:
+                iconIdentifier: 't3-form-icon-validator'
+                label: 'formEditor.elements.DatePicker.validators.DateTime.editor.header.label'
+            Alphanumeric:
+              formEditor:
+                iconIdentifier: 't3-form-icon-validator'
+                label: 'formEditor.elements.TextMixin.editor.validators.Alphanumeric.label'
+            Text:
+              formEditor:
+                iconIdentifier: 't3-form-icon-validator'
+                label: 'formEditor.elements.TextMixin.editor.validators.Text.label'
+            StringLength:
+              formEditor:
+                iconIdentifier: 't3-form-icon-validator'
+                label: 'formEditor.elements.TextMixin.editor.validators.StringLength.label'
+                predefinedDefaults:
+                  options:
+                    minimum: ''
+                    maximum: ''
+            EmailAddress:
+              formEditor:
+                iconIdentifier: 't3-form-icon-validator'
+                label: 'formEditor.elements.TextMixin.editor.validators.EmailAddress.label'
+            Integer:
+              formEditor:
+                iconIdentifier: 't3-form-icon-validator'
+                label: 'formEditor.elements.TextMixin.editor.validators.Integer.label'
+            Float:
+              formEditor:
+                iconIdentifier: 't3-form-icon-validator'
+                label: 'formEditor.elements.TextMixin.editor.validators.Float.label'
+            NumberRange:
+              formEditor:
+                iconIdentifier: 't3-form-icon-validator'
+                label: 'formEditor.elements.TextMixin.editor.validators.NumberRange.label'
+                predefinedDefaults:
+                  options:
+                    minimum: ''
+                    maximum: ''
+            RegularExpression:
+              formEditor:
+                iconIdentifier: 't3-form-icon-validator'
+                label: 'formEditor.elements.TextMixin.editor.validators.RegularExpression.label'
+                predefinedDefaults:
+                  options:
+                    regularExpression: ''
+            Count:
+              formEditor:
+                iconIdentifier: 't3-form-icon-validator'
+                label: 'formEditor.elements.MultiSelectionMixin.validators.Count.editor.header.label'
+                predefinedDefaults:
+                  options:
+                    minimum: ''
+                    maximum: ''
+
+      ########### MIXINS ###########
+      mixins:
+        ########### FORM ELEMENT MIXINS ###########
+        formElementMixins:
+          BaseFormElementMixin:
+            formEditor:
+              predefinedDefaults:
+              editors:
+                100:
+                  identifier: 'header'
+                  templateName: 'Inspector-FormElementHeaderEditor'
+                200:
+                  identifier: 'label'
+                  templateName: 'Inspector-TextEditor'
+                  label: 'formEditor.elements.BaseFormElementMixin.editor.label.label'
+                  propertyPath: 'label'
+
+          RemoveButtonMixin:
+            9999:
+              identifier: 'removeButton'
+              templateName: 'Inspector-RemoveElementEditor'
+
+          RemovableFormElementMixin:
+            editors:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.RemoveButtonMixin'
+
+          BaseCollectionEditorsMixin:
+            __inheritances:
+              10: 'TYPO3.CMS.Form.mixins.formElementMixins.RemoveButtonMixin'
+            100:
+              identifier: 'header'
+              templateName: 'Inspector-CollectionElementHeaderEditor'
+              label: ''
+
+          MinimumMaximumEditorsMixin:
+            200:
+              identifier: 'minimum'
+              templateName: 'Inspector-TextEditor'
+              label: 'formEditor.elements.MinimumMaximumEditorsMixin.editor.minimum.label'
+              propertyPath: 'options.minimum'
+              propertyValidatorsMode: 'OR'
+              propertyValidators:
+                10: 'Integer'
+                20: 'FormElementIdentifierWithinCurlyBracesExclusive'
+            300:
+              identifier: 'maximum'
+              templateName: 'Inspector-TextEditor'
+              label: 'formEditor.elements.MinimumMaximumEditorsMixin.editor.maximum.label'
+              propertyPath: 'options.maximum'
+              propertyValidatorsMode: 'OR'
+              propertyValidators:
+                10: 'Integer'
+                20: 'FormElementIdentifierWithinCurlyBracesExclusive'
+
+          ReadOnlyFormElementMixin:
+            formEditor:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.RemovableFormElementMixin'
+              editors:
+                200:
+                  label: 'formEditor.elements.ReadOnlyFormElement.editor.label.label'
+
+          FormElementMixin:
+            formEditor:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.RemovableFormElementMixin'
+              editors:
+                200:
+                  label: 'formEditor.elements.FormElement.editor.label.label'
+                800:
+                  identifier: 'requiredValidator'
+                  templateName: 'Inspector-RequiredValidatorEditor'
+                  label: 'formEditor.elements.FormElement.editor.requiredValidator.label'
+                  validatorIdentifier: 'NotEmpty'
+
+          TextMixin:
+            formEditor:
+              predefinedDefaults:
+                properties:
+                  placeholder: ''
+                defaultValue: ''
+              editors:
+                400:
+                  identifier: 'placeholder'
+                  templateName: 'Inspector-TextEditor'
+                  label: 'formEditor.elements.TextMixin.editor.placeholder.label'
+                  propertyPath: 'properties.placeholder'
+                500:
+                  identifier: 'defaultValue'
+                  templateName: 'Inspector-TextEditor'
+                  label: 'formEditor.elements.TextMixin.editor.defaultValue.label'
+                  propertyPath: 'defaultValue'
+                900:
+                  identifier: 'validators'
+                  templateName: 'Inspector-ValidatorsEditor'
+                  label: 'formEditor.elements.TextMixin.editor.validators.label'
+                  selectOptions:
+                    10:
+                      value: ''
+                      label: 'formEditor.elements.TextMixin.editor.validators.EmptyValue.label'
+                    20:
+                      value: 'Alphanumeric'
+                      label: 'formEditor.elements.TextMixin.editor.validators.Alphanumeric.label'
+                    30:
+                      value: 'Text'
+                      label: 'formEditor.elements.TextMixin.editor.validators.Text.label'
+                    40:
+                      value: 'StringLength'
+                      label: 'formEditor.elements.TextMixin.editor.validators.StringLength.label'
+                    50:
+                      value: 'EmailAddress'
+                      label: 'formEditor.elements.TextMixin.editor.validators.EmailAddress.label'
+                    60:
+                      value: 'Integer'
+                      label: 'formEditor.elements.TextMixin.editor.validators.Integer.label'
+                    70:
+                      value: 'Float'
+                      label: 'formEditor.elements.TextMixin.editor.validators.Float.label'
+                    80:
+                      value: 'NumberRange'
+                      label: 'formEditor.elements.TextMixin.editor.validators.NumberRange.label'
+                    90:
+                      value: 'RegularExpression'
+                      label: 'formEditor.elements.TextMixin.editor.validators.RegularExpression.label'
+
+              propertyCollections:
+                validators:
+                  10:
+                    identifier: 'Alphanumeric'
+                    editors:
+                      __inheritances:
+                        10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                      100:
+                        label: 'formEditor.elements.TextMixin.validators.Alphanumeric.editor.header.label'
+                  20:
+                    identifier: 'Text'
+                    editors:
+                      __inheritances:
+                        10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                      100:
+                        label: 'formEditor.elements.TextMixin.validators.Text.editor.header.label'
+                  30:
+                    identifier: 'StringLength'
+                    editors:
+                      __inheritances:
+                        10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                        20: 'TYPO3.CMS.Form.mixins.formElementMixins.MinimumMaximumEditorsMixin'
+                      100:
+                        label: 'formEditor.elements.TextMixin.validators.StringLength.editor.header.label'
+                  40:
+                    identifier: 'EmailAddress'
+                    editors:
+                      __inheritances:
+                        10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                      100:
+                        label: 'formEditor.elements.TextMixin.validators.EmailAddress.editor.header.label'
+                  50:
+                    identifier: 'Integer'
+                    editors:
+                      __inheritances:
+                        10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                      100:
+                        label: 'formEditor.elements.TextMixin.validators.Integer.editor.header.label'
+                  60:
+                    identifier: 'Float'
+                    editors:
+                      __inheritances:
+                        10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                      100:
+                        label: 'formEditor.elements.TextMixin.validators.Float.editor.header.label'
+                  70:
+                    identifier: 'NumberRange'
+                    editors:
+                      __inheritances:
+                        10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                        20: 'TYPO3.CMS.Form.mixins.formElementMixins.MinimumMaximumEditorsMixin'
+                      100:
+                        label: 'formEditor.elements.TextMixin.validators.NumberRange.editor.header.label'
+                  80:
+                    identifier: 'RegularExpression'
+                    editors:
+                      __inheritances:
+                        10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                      100:
+                        label: 'formEditor.elements.TextMixin.validators.RegularExpression.editor.header.label'
+                      200:
+                        identifier: 'regex'
+                        templateName: 'Inspector-TextEditor'
+                        label: 'formEditor.elements.TextMixin.validators.RegularExpression.editor.regex.label'
+                        fieldExplanationText: 'formEditor.elements.TextMixin.validators.RegularExpression.editor.regex.fieldExplanationText'
+                        propertyPath: 'options.regularExpression'
+                        propertyValidators:
+                          10: 'NotEmpty'
+
+          SelectionMixin:
+            formEditor:
+              predefinedDefaults:
+                properties:
+                  options: []
+              editors:
+                300:
+                  identifier: 'options'
+                  templateName: 'Inspector-PropertyGridEditor'
+                  label: 'formEditor.elements.SelectionMixin.editor.options.label'
+                  propertyPath: 'properties.options'
+                  isSortable: true
+                  enableAddRow: true
+                  enableDeleteRow: true
+                  removeLastAvailableRowFlashMessageTitle: 'formEditor.elements.SelectionMixin.editor.options.removeLastAvailableRowFlashMessageTitle'
+                  removeLastAvailableRowFlashMessageMessage: 'formEditor.elements.SelectionMixin.editor.options.removeLastAvailableRowFlashMessageMessage'
+
+          SingleSelectionMixin:
+            formEditor:
+              editors:
+                300:
+                  shouldShowPreselectedValueColumn: 'single'
+                  multiSelection: false
+
+          MultiSelectionMixin:
+            formEditor:
+              editors:
+                300:
+                  shouldShowPreselectedValueColumn: 'multiple'
+                  multiSelection: true
+                900:
+                  identifier: 'validators'
+                  templateName: 'Inspector-ValidatorsEditor'
+                  label: 'formEditor.elements.MultiSelectionMixin.editor.validators.label'
+                  selectOptions:
+                    10:
+                      value: ''
+                      label: 'formEditor.elements.MultiSelectionMixin.editor.validators.EmptyValue.label'
+                    20:
+                      value: 'Count'
+                      label: 'formEditor.elements.MultiSelectionMixin.editor.validators.Count.label'
+
+              propertyCollections:
+                validators:
+                  10:
+                    identifier: 'Count'
+                    editors:
+                      __inheritances:
+                        10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+                        20: 'TYPO3.CMS.Form.mixins.formElementMixins.MinimumMaximumEditorsMixin'
+                      100:
+                        label: 'formEditor.elements.MultiSelectionMixin.validators.Count.editor.header.label'
+
+          FileUploadMixin:
+            formEditor:
+              predefinedDefaults:
+                properties:
+                  saveToFileMount: '1:/user_upload/'
+              editors:
+                400:
+                  identifier: 'saveToFileMount'
+                  templateName: 'Inspector-SingleSelectEditor'
+                  label: 'formEditor.elements.FileUploadMixin.editor.saveToFileMount.label'
+                  propertyPath: 'properties.saveToFileMount'
+                  selectOptions:
+                    10:
+                      value: '1:/user_upload/'
+                      label: '1:/user_upload/'
+
+          formEmailFinisherMixin:
+            editors:
+              __inheritances:
+                10: 'TYPO3.CMS.Form.mixins.formElementMixins.BaseCollectionEditorsMixin'
+              100:
+                label: 'formEditor.elements.Form.finisher.EmailToSender.editor.header.label'
+              200:
+                identifier: 'subject'
+                templateName: 'Inspector-TextEditor'
+                label: 'formEditor.elements.Form.finisher.EmailToSender.editor.subject.label'
+                propertyPath: 'options.subject'
+                propertyValidators:
+                  10: 'NotEmpty'
+                  20: 'FormElementIdentifierWithinCurlyBracesInclusive'
+              300:
+                identifier: 'recipientAddress'
+                templateName: 'Inspector-TextEditor'
+                label: 'formEditor.elements.Form.finisher.EmailToSender.editor.recipientAddress.label'
+                propertyPath: 'options.recipientAddress'
+                propertyValidatorsMode: 'OR'
+                propertyValidators:
+                  10: 'NaiveEmail'
+                  20: 'FormElementIdentifierWithinCurlyBracesExclusive'
+              400:
+                identifier: 'recipientName'
+                templateName: 'Inspector-TextEditor'
+                label: 'formEditor.elements.Form.finisher.EmailToSender.editor.recipientName.label'
+                propertyPath: 'options.recipientName'
+              500:
+                identifier: 'senderAddress'
+                templateName: 'Inspector-TextEditor'
+                label: 'formEditor.elements.Form.finisher.EmailToSender.editor.senderAddress.label'
+                propertyPath: 'options.senderAddress'
+                propertyValidatorsMode: 'OR'
+                propertyValidators:
+                  10: 'NaiveEmail'
+                  20: 'FormElementIdentifierWithinCurlyBracesExclusive'
+              600:
+                identifier: 'senderName'
+                templateName: 'Inspector-TextEditor'
+                label: 'formEditor.elements.Form.finisher.EmailToSender.editor.senderName.label'
+                propertyPath: 'options.senderName'
+              700:
+                identifier: 'replyToAddress'
+                templateName: 'Inspector-TextEditor'
+                label: 'formEditor.elements.Form.finisher.EmailToSender.editor.replyToAddress.label'
+                propertyPath: 'options.replyToAddress'
+                propertyValidatorsMode: 'OR'
+                propertyValidators:
+                  10: 'NaiveEmailOrEmpty'
+                  20: 'FormElementIdentifierWithinCurlyBracesExclusive'
+              800:
+                identifier: 'carbonCopyAddress'
+                templateName: 'Inspector-TextEditor'
+                label: 'formEditor.elements.Form.finisher.EmailToSender.editor.carbonCopyAddress.label'
+                propertyPath: 'options.carbonCopyAddress'
+                propertyValidatorsMode: 'OR'
+                propertyValidators:
+                  10: 'NaiveEmailOrEmpty'
+                  20: 'FormElementIdentifierWithinCurlyBracesExclusive'
+              900:
+                identifier: 'blindCarbonCopyAddress'
+                templateName: 'Inspector-TextEditor'
+                label: 'formEditor.elements.Form.finisher.EmailToSender.editor.blindCarbonCopyAddress.label'
+                propertyPath: 'options.blindCarbonCopyAddress'
+                propertyValidatorsMode: 'OR'
+                propertyValidators:
+                  10: 'NaiveEmailOrEmpty'
+                  20: 'FormElementIdentifierWithinCurlyBracesExclusive'
+              1000:
+                identifier: 'format'
+                templateName: 'Inspector-SingleSelectEditor'
+                label: 'formEditor.elements.Form.finisher.EmailToSender.editor.format.label'
+                propertyPath: 'options.format'
+                selectOptions:
+                  10:
+                    value: 'plaintext'
+                    label: 'formEditor.elements.Form.finisher.EmailToSender.editor.format.1'
+                  20:
+                    value: 'html'
+                    label: 'formEditor.elements.Form.finisher.EmailToSender.editor.format.2'
+              1100:
+                identifier: 'attachUploads'
+                templateName: 'Inspector-CheckboxEditor'
+                label: 'formEditor.elements.Form.finisher.EmailToSender.editor.attachUploads.label'
+                propertyPath: 'options.attachUploads'
\ No newline at end of file
diff --git a/typo3/sysext/form/Configuration/Yaml/FormEngineSetup.yaml b/typo3/sysext/form/Configuration/Yaml/FormEngineSetup.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e67943029be475e3fb787ed3096ef3774d987d15
--- /dev/null
+++ b/typo3/sysext/form/Configuration/Yaml/FormEngineSetup.yaml
@@ -0,0 +1,132 @@
+TYPO3:
+  CMS:
+    Form:
+      prototypes:
+        standard:
+          ########### TCE Forms CONFIGURATION ###########
+
+          ### FINISHERS ###
+          finishersDefinition:
+            EmailToSender:
+              FormEngine:
+                __inheritances:
+                  10: 'TYPO3.CMS.Form.mixins.FormEngineEmailMixin'
+
+            EmailToReceiver:
+              FormEngine:
+                __inheritances:
+                  10: 'TYPO3.CMS.Form.mixins.FormEngineEmailMixin'
+                label: 'tt_content.finishersDefinition.EmailToReceiver.label'
+                elements:
+                  subject:
+                    label: 'tt_content.finishersDefinition.EmailToReceiver.subject.label'
+                  recipientAddress:
+                    label: 'tt_content.finishersDefinition.EmailToReceiver.recipientAddress.label'
+                  recipientName:
+                    label: 'tt_content.finishersDefinition.EmailToReceiver.recipientName.label'
+                  senderAddress:
+                    label: 'tt_content.finishersDefinition.EmailToReceiver.senderAddress.label'
+                  senderName:
+                    label: 'tt_content.finishersDefinition.EmailToReceiver.senderName.label'
+                  replyToAddress:
+                    label: 'tt_content.finishersDefinition.EmailToReceiver.replyToAddress.label'
+                  carbonCopyAddress:
+                    label: 'tt_content.finishersDefinition.EmailToReceiver.carbonCopyAddress.label'
+                  blindCarbonCopyAddress:
+                    label: 'tt_content.finishersDefinition.EmailToReceiver.blindCarbonCopyAddress.label'
+                  format:
+                    label: 'tt_content.finishersDefinition.EmailToReceiver.format.label'
+                  translation:
+                    language:
+                      label: 'tt_content.finishersDefinition.EmailToReceiver.language.label'
+                      config:
+                        type: select
+                        renderType: 'selectSingle'
+                        minitems: 1
+                        maxitems: 1
+                        size: 1
+                        items:
+                          10:
+                            0: 'tt_content.finishersDefinition.EmailToReceiver.language.1'
+                            1: 'default'
+
+            Redirect:
+              FormEngine:
+                __inheritances:
+                  10: 'TYPO3.CMS.Form.mixins.FormEngineTranslationSettingsMixin'
+                label: 'tt_content.finishersDefinition.Redirect.label'
+                elements:
+                  pageUid:
+                    label: 'tt_content.finishersDefinition.Redirect.pageUid.label'
+                    config:
+                      type: 'group'
+                      internal_type: 'db'
+                      allowed: 'pages'
+                      size: 1
+                      minitems: 1
+                      maxitems: 1
+                      show_thumbs: 0
+                  additionalParameters:
+                    label: 'tt_content.finishersDefinition.Redirect.additionalParameters.label'
+                    config:
+                      type: 'input'
+
+      ########### MIXINS ###########
+      mixins:
+        FormEngineTranslationSettingsMixin:
+          translationFile: 'EXT:form/Resources/Private/Language/Database.xlf'
+
+        FormEngineEmailMixin:
+          __inheritances:
+            10: 'TYPO3.CMS.Form.mixins.FormEngineTranslationSettingsMixin'
+          label: 'tt_content.finishersDefinition.EmailToSender.label'
+          elements:
+            subject:
+              label: 'tt_content.finishersDefinition.EmailToSender.subject.label'
+              config:
+                type: 'input'
+            recipientAddress:
+              label: 'tt_content.finishersDefinition.EmailToSender.recipientAddress.label'
+              config:
+                type: 'input'
+                eval: 'required'
+            recipientName:
+              label: 'tt_content.finishersDefinition.EmailToSender.recipientName.label'
+              config:
+                type: 'input'
+            senderAddress:
+              label: 'tt_content.finishersDefinition.EmailToSender.senderAddress.label'
+              config:
+                type: 'input'
+                eval: 'required'
+            senderName:
+              label: 'tt_content.finishersDefinition.EmailToSender.senderName.label'
+              config:
+                type: 'input'
+            replyToAddress:
+              label: 'tt_content.finishersDefinition.EmailToSender.replyToAddress.label'
+              config:
+                type: 'input'
+            carbonCopyAddress:
+              label: 'tt_content.finishersDefinition.EmailToSender.carbonCopyAddress.label'
+              config:
+                type: 'input'
+            blindCarbonCopyAddress:
+              label: 'tt_content.finishersDefinition.EmailToSender.blindCarbonCopyAddress.label'
+              config:
+                type: 'input'
+            format:
+              label: 'tt_content.finishersDefinition.EmailToSender.format.label'
+              config:
+                type: select
+                renderType: 'selectSingle'
+                minitems: 1
+                maxitems: 1
+                size: 1
+                items:
+                  10:
+                    0: 'tt_content.finishersDefinition.EmailToSender.format.1'
+                    1: 'html'
+                  20:
+                    0: 'tt_content.finishersDefinition.EmailToSender.format.2'
+                    1: 'plaintext'
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/.gitignore b/typo3/sysext/form/Documentation/.gitignore
deleted file mode 100644
index 6cd159f2dad9a4583183510425d81e948207903b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-# this is file .gitignore
-
-# ignore everything in this directory
-_make/*
-
-# but do not ignore this file
-!_not_versioned/.gitignore
diff --git a/typo3/sysext/form/Documentation/Administration/DefaultNewRecord/Index.rst b/typo3/sysext/form/Documentation/Administration/DefaultNewRecord/Index.rst
deleted file mode 100644
index 2d3fafad982d76d48d7a569e71a3c214ccca4a67..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Administration/DefaultNewRecord/Index.rst
+++ /dev/null
@@ -1,38 +0,0 @@
-.. include:: ../../Includes.txt
-
-
-.. _default-new-record:
-
-==================
-Default new record
-==================
-
-When an editor creates a new FORM record, the bodytext will be filled by
-default with some simple form settings which are displayed below. The
-integrator can change this setting to specific needs, but this string
-**cannot be big due to some core limitations**. It is impossible to add
-the configuration for a complete form, although it might be a simple one.
-This restriction is caused by the fact that the whole string is put in
-a URI as parameter.
-
-Furthermore this only works when the editor is using the web module, i.e.
-the functionality is not supported by the list module.
-
-.. code-block:: typoscript
-
-  mod.wizards {
-    newContentElement.wizardItems {
-      forms.elements {
-        mailform {
-          tt_content_defValues {
-            bodytext (
-  enctype = multipart/form-data
-  method = post
-  prefix = tx_form
-            )
-          }
-        }
-      }
-    }
-  }
-
diff --git a/typo3/sysext/form/Documentation/Administration/Index.rst b/typo3/sysext/form/Documentation/Administration/Index.rst
deleted file mode 100644
index e04e183534481963f0dd1d30cb118a9f95367545..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Administration/Index.rst
+++ /dev/null
@@ -1,23 +0,0 @@
-.. include:: ../Includes.txt
-
-
-.. _administration:
-
-==============
-Administration
-==============
-
-Upon installation, the extension will set default properties in the page
-TSconfig in the variable :ts:`mod.wizards`.
-
-These properties may be modified for any particular page, BE user or BE
-user group and are described below.
-
-.. toctree::
-    :maxdepth: 5
-    :titlesonly:
-    :glob:
-
-    DefaultNewRecord/Index
-    WizardSettings/Index
-
diff --git a/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/ElementsTab/Index.rst b/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/ElementsTab/Index.rst
deleted file mode 100644
index ad2f016ce0b2bbdfd9b24063680bdc60b6f6d10f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/ElementsTab/Index.rst
+++ /dev/null
@@ -1,131 +0,0 @@
-.. include:: ../../../../Includes.txt
-
-
-.. _wizard-settings-defaults-elements-tab:
-
-==============
-Tab "Elements"
-==============
-
-The elements tab contains an accordion with buttons, grouped by their
-type. These buttons identify a form element, like a text field, password
-field or submit button. When dragging a button to the form on the right
-and dropping it at a certain point in the form, the element will be added
-to the form at that point. An editor can also double click a button. When
-doing so, the element will be added at the end of the form.
-
-.. figure:: ../../../../Images/FormCreationWizardElementsTab.png
-    :alt: The form wizard with the tab "Elements".
-
-.. contents::
-    :local:
-    :depth: 1
-
-
-.. _wizard-settings-defaults-elements-showaccordions:
-
-showAccordions
-==============
-
-(:ts:`mod.wizards.form.defaults.tabs.elements.showAccordions`)
-
-:aspect:`Property:`
-    showAccordions
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Comma-separated list of the accordions that will be shown in the
-    wizard. Each of the three accordions contain a single showButton
-    property which defines which form elements will be shown in a given
-    accordion.
-
-:aspect:`Default:`
-    basic, predefined, content
-
-
-.. _wizard-settings-defaults-elements-accordions-showbuttons:
-
-showButtons
-===========
-
-(:ts:`mod.wizards.form.defaults.tabs.elements.accordions.[NameOfAccordion].showButtons`)
-
-:aspect:`Property:`
-    showButtons
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Comma-separated list of the buttons that will be shown in the accordion.
-    Please note, in the shown path has [NameOfAccordion] to be replaced with
-    the name of the specific accordion.
-
-:aspect:`Default:`
-    **"basic" elements**
-
-    - textline (Text Field)
-    - textarea (Textarea)
-    - checkbox (Checkbox)
-    - radio (Radio Button)
-    - select (Drop Down)
-    - fileupload (Upload Field)
-    - hidden (Hidden Field)
-    - password (Password Field)
-    - fieldset (Fieldset)
-    - submit (Submit Button)
-    - reset (Reset Button)
-    - button (Button)
-
-    |
-
-    **"predefined" elements**
-
-    - name (Full Name)
-    - email (Email)
-    - checkboxgroup (Checkbox Group)
-    - radiogroup (Radio Button Group)
-
-    |
-
-    **"content" elements**
-
-    - header (Header)
-    - textblock (Text Block)
-
-
-.. _wizard-settings-defaults-elements-tab-configuration:
-
-Default configuration
-=====================
-
-The default configuration of the elements tab is as follows.
-
-.. code-block:: typoscript
-
-  mod.wizards {
-    form {
-      defaults {
-        showTabs = elements, options, form
-        tabs {
-          elements {
-            showAccordions = basic, predefined, content
-            accordions {
-              basic {
-                showButtons = textline, textarea, checkbox, radio, select, fileupload, hidden, password, fieldset, submit, reset, button
-              }
-              predefined {
-                showButtons = name, email, checkboxgroup, radiogroup
-              }
-              content {
-                showButtons = header, textblock
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
diff --git a/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/FormTab/Index.rst b/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/FormTab/Index.rst
deleted file mode 100644
index d6f2066ad1667ec1b0a79d6018888e57decd170a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/FormTab/Index.rst
+++ /dev/null
@@ -1,187 +0,0 @@
-.. include:: ../../../../Includes.txt
-
-
-.. _wizard-settings-defaults-form-tab:
-
-==========
-Tab "Form"
-==========
-
-The form tab shows the configuration of the outer form, like the attributes
-of the form or the prefix as well as the post-processor configuration.
-
-.. figure:: ../../../../Images/FormCreationWizardFormTab.png
-    :alt: The form wizard with the tab "Form".
-
-.. contents::
-    :local:
-    :depth: 1
-
-
-.. _wizard-settings-defaults-form-showaccordions:
-
-showAccordions
-==============
-
-(:ts:`mod.wizards.form.defaults.tabs.form.showAccordions`)
-
-:aspect:`Property:`
-    showAccordions
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Comma-separated list of the accordions that are allowed to be shown in
-    the wizard. This does not mean they are all shown by default, but
-    depends on the chosen element type.
-
-    Some accordions have further properties, which are described below.
-
-:aspect:`Default:`
-    The following accordions are available in the form tab:
-
-    * behaviour
-    * prefix
-    * :ref:`attributes <wizard-settings-defaults-form-attributes>`
-    * :ref:`postProcessor <wizard-settings-defaults-form-postprocessor>`
-
-
-.. _wizard-settings-defaults-form-attributes:
-
-Attributes accordion
-====================
-
-
-.. _wizard-settings-defaults-form-attributes-showproperties:
-
-showProperties
---------------
-
-.. attention::
-
-    The configuration of the attributes accordion is not working as
-    expected and has to be fixed in a coming version of TYPO3. There is
-    a workaround which is shown below.
-
-(:ts:`mod.wizards.form.defaults.tabs.form.accordions.attributes.showProperties`)
-
-:aspect:`Property:`
-    showProperties
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Comma-separated list of the form attributes that are allowed to be shown
-    in the accordion.
-
-:aspect:`Default:`
-    accept, action, dir, enctype, lang, method, novalidate, class, id, style, title
-
-Since the above shown configuration is not working, the following workaround can
-be applied. To configure the attribute accordion of the form element, address the
-object directly via :ts:`mod.wizards.form.elements.form.accordions.attributes.showProperties`.
-
-
-.. _wizard-settings-defaults-form-postprocessor:
-
-Post-processors accordion
-=========================
-
-
-.. _wizard-settings-defaults-form-postprocessor-showpostprocessors:
-
-showPostProcessors
-------------------
-
-(:ts:`mod.wizards.form.defaults.tabs.form.accordions.postProcessor.showPostProcessors`)
-
-:aspect:`Property:`
-    showPostProcessors
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-   Comma-separated list of the post-processors that are allowed to be shown
-   in the wizard.
-
-   For each post-processors a list of properties to be shown can be defined.
-
-:aspect:`Default:`
-    mail, redirect
-
-
-.. _wizard-settings-defaults-options-postprocessor-postprocessors:
-
-postProcessors.[post-processor].showProperties
-----------------------------------------------
-
-(:ts:`mod.wizards.form.defaults.tabs.form.accordions.postProcessor.postProcessors.[post-processor].showProperties`)
-
-:aspect:`Property:`
-    postProcessors.[post-processor].showProperties
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Configuration for the post-processors individually.
-
-    The syntax is :ts:`postProcessors.[name of the post-processor].showProperties`.
-
-:aspect:`Default:`
-    The following element properties are available:
-
-    .. t3-field-list-table::
-        :header-rows: 1
-
-        - :Field:
-                Element:
-          :Description:
-                Properties:
-        - :Field:
-                mail
-          :Description:
-                recipientEmail, senderEmail, subject
-        - :Field:
-                redirect
-          :Description:
-                destination
-
-
-.. _wizard-settings-defaults-form-tab-configuration:
-
-Default configuration
-=====================
-
-The default configuration of the form tab looks as follows:
-
-.. code-block:: typoscript
-
-  mod.wizards {
-    form {
-      defaults {
-        tabs {
-          form {
-            showAccordions = behaviour, prefix, attributes, postProcessor
-            accordions {
-              postProcessor {
-                showPostProcessors = mail, redirect
-                postProcessors {
-                  mail {
-                    showProperties = recipientEmail, senderEmail, subject
-                  }
-                  redirect {
-                    showProperties = destination
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
diff --git a/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/Index.rst b/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/Index.rst
deleted file mode 100644
index 44a5e56f60baa3474032aea5f8acbfa53384ffee..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/Index.rst
+++ /dev/null
@@ -1,24 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _wizard-settings-defaults:
-
-==================
-Defaults reference
-==================
-
-This chapter describes the settings for the visible tabs, the accordions
-available inside these tabs and the default configuration for all element
-types.
-
-
-.. toctree::
-    :maxdepth: 5
-    :titlesonly:
-    :glob:
-
-    ShowTabs/Index
-    ElementsTab/Index
-    OptionsTab/Index
-    FormTab/Index
-
diff --git a/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/OptionsTab/Index.rst b/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/OptionsTab/Index.rst
deleted file mode 100644
index 8b0b89f3a1abde168fb0d8cb79c512b73b40d6a7..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/OptionsTab/Index.rst
+++ /dev/null
@@ -1,404 +0,0 @@
-.. include:: ../../../../Includes.txt
-
-
-.. _wizard-settings-defaults-options-tab:
-
-=============
-Tab "Options"
-=============
-
-The options tab will show the configuration of a particular element in
-the form. When no element has been selected, it will show a message that
-the editor has to select an element in the form.
-
-The content of this tab depends on the type of element the editor has chosen
-in the form.
-
-.. figure:: ../../../../Images/FormCreationWizardOptionsTab.png
-    :alt: The form wizard with the tab "Options".
-
-.. contents::
-    :local:
-    :depth: 1
-
-
-.. _wizard-settings-defaults-options-showaccordions:
-
-showAccordions
-==============
-
-:aspect:`Property:`
-    showAccordions
-
-:aspect:`TypoScript Path:`
-    :ts:`mod.wizards.form.defaults.tabs.options.showAccordions`
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Comma-separated list of the accordions that are allowed to be shown
-    in the wizard. This does not mean they are all shown by default,
-    but depends on the chosen element type.
-
-    Some tabs have further configuration which is described below.
-
-:aspect:`Default:`
-    The following accordions are available:
-
-    - *legend*: Legend Properties
-    - *label*: :ref:`Label Properties <wizard-settings-defaults-options-label>`
-    - *attributes*: :ref:`Attributes Properties <wizard-settings-defaults-options-attributes>`
-    - *options*: Field Options
-    - *validation*: :ref:`Validation <wizard-settings-defaults-validation-label>`
-    - *filters*: :ref:`Filters <wizard-settings-defaults-filters-label>`
-    - *various*: Various Properties
-
-:aspect:`Example:`
-    .. code-block:: typoscript
-
-      mod.wizards {
-        form {
-          defaults {
-            tabs {
-              options {
-                showAccordions = legend, label, attributes, options, validation, filters, various
-              }
-            }
-          }
-
-        }
-      }
-
-
-.. _wizard-settings-defaults-options-label:
-
-Label accordion
-===============
-
-
-.. _wizard-settings-defaults-options-label-showproperties:
-
-showProperties
---------------
-
-:aspect:`Property:`
-    showProperties
-
-:aspect:`TypoScript Path:`
-    :ts:`mod.wizards.form.defaults.tabs.options.accordions.label.showProperties`
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Comma-separated list of the label options that are allowed to be shown
-    in the accordion. The appearance of an option depends on the chosen
-    element type. If an element type does not support an option, it will not
-    be shown.
-
-:aspect:`Default:`
-    label
-
-
-.. _wizard-settings-defaults-options-attributes:
-
-Attributes accordion
-====================
-
-
-.. _wizard-settings-defaults-options-attributes-showproperties:
-
-showProperties
---------------
-
-:aspect:`Property:`
-    showProperties
-
-:aspect:`TypoScript Path:`
-    :ts:`mod.wizards.form.defaults.tabs.options.accordions.attributes.showProperties`
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Comma-separated list of attributes that are allowed to be shown in the
-    accordion. The appearance of an attribute depends on the chosen element
-    type. If an element type does not support an attribute, it will not be
-    shown.
-
-
-:aspect:`Default:`
-    accept, accept-charset, accesskey, action, alt, autocomplete, autofocus,
-    checked, class, cols, contenteditable, contextmenu, dir, draggable,
-    dropzone, disabled, enctype, hidden, height, id, inputmode, label, lang,
-    list, max, maxlength, method, min, minlength, multiple, name,
-    novalidate, pattern, placeholder, readonly, required, rows, selected,
-    selectionDirection, selectionEnd, selectionStart, size, spellcheck, src,
-    step, style, tabindex, text, title, translate, type, value, width, wrap
-
-
-.. _wizard-settings-defaults-validation-label:
-
-Validation accordion
-====================
-
-
-.. _wizard-settings-defaults-options-validation-showrules:
-
-showRules
----------
-
-:aspect:`Property:`
-    showRules
-
-:aspect:`TypoScript Path:`
-    :ts:`mod.wizards.form.defaults.tabs.options.accordions.validation.showRules`
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Comma-separated list of rules that are allowed to be shown in the
-    wizard.
-
-:aspect:`Default:`
-    alphabetic, alphanumeric, between, date, digit, email, equals,
-    fileallowedtypes, filemaximumsize, fileminimumsize, float, greaterthan,
-    inarray, integer, ip, length, lessthan, regexp, required, uri
-
-
-.. _wizard-settings-defaults-options-validation-rules:
-
-rules.[rule].showProperties
----------------------------
-
-:aspect:`Property:`
-    rules.[rule].showProperties
-
-:aspect:`TypoScript Path:`
-    :ts:`mod.wizards.form.defaults.tabs.options.accordions.validation.rules.[rule].showProperties`
-
-:aspect:`Data type:`
-    [array of objects]
-
-:aspect:`Description:`
-    For each rule one can define which properties should appear.
-    The syntax is :ts:`rules.[name of the rule].showProperties`.
-
-:aspect:`Default:`
-    The following element properties are available:
-
-    =================== ========================================================
-    Element             Properties
-    =================== ========================================================
-    alphabetic          message, error, showMessage, allowWhiteSpace
-    alphanumeric        message, error, showMessage, allowWhiteSpace
-    between             message, error, showMessage, minimum, maximum, inclusive
-    date                message, error, showMessage, format
-    digit               message, error, showMessage
-    email               message, error, showMessage
-    equals              message, error, showMessage, field
-    fileallowedtypes    message, error, showMessage, types
-    filemaximumsize     message, error, showMessage, maximum
-    fileminimumsize     message, error, showMessage, minimum
-    float               message, error, showMessage
-    greaterthan         message, error, showMessage, minimum
-    inarray             message, error, showMessage, array, strict
-    integer             message, error, showMessage
-    ip                  message, error, showMessage
-    length              message, error, showMessage, minimum, maximum
-    lessthan            message, error, showMessage, maximum
-    regexp              message, error, showMessage, expression
-    required            message, error, showMessage
-    uri                 message, error, showMessage
-    =================== ========================================================
-
-
-.. _wizard-settings-defaults-filters-label:
-
-Filters accordion
-=================
-
-
-.. _wizard-settings-defaults-options-filtering-showfilters:
-
-showFilters
------------
-
-:aspect:`Property:`
-    showFilters
-
-:aspect:`TypoScript Path:`
-    :ts:`mod.wizards.form.defaults.tabs.options.accordions.filtering.showFilters`
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Comma-separated list of the filters that are allowed to be shown in
-    the wizard.
-
-    For each filter a list of properties to be shown can be defined.
-
-:aspect:`Default:`
-    alphabetic, alphanumeric, currency, digit, integer, lowercase, regexp,
-    stripnewlines, titlecase, trim, uppercase
-
-
-.. _wizard-settings-defaults-options-filtering-filters:
-
-filters.[filter].showProperties
--------------------------------
-
-:aspect:`Property:`
-    filters.[filter].showProperties
-
-:aspect:`TypoScript Path:`
-    :ts:`mod.wizards.form.defaults.tabs.options.accordions.filtering.filters.[filter].showProperties`
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Configuration for the filters individually. Not all filters have a
-    configuration. Only the filters which are mentioned below can be
-    configured.
-
-    The syntax is :ts:`filters.[name of the filter].showProperties`.
-
-:aspect:`Default:`
-    The following element properties are available:
-
-    =================== ===============================
-    Element             Properties
-    =================== ===============================
-    alphabetic          allowWhiteSpace
-    alphanumeric        allowWhiteSpace
-    currency            decimalPoint, thousandSeparator
-    regexp              expression
-    trim                characterList
-    =================== ===============================
-
-
-.. _wizard-settings-defaults-options-tab-configuration:
-
-Default configuration
-=====================
-
-The default configuration of the options tab looks like this:
-
-.. code-block:: typoscript
-
-  options {
-     showAccordions = legend, label, attributes, options, validation, filters, various
-     accordions {
-         label {
-            showProperties = label
-         }
-         attributes {
-            showProperties = accept, accept-charset, accesskey, action, alt, autocomplete, autofocus, checked, class, cols, contenteditable, contextmenu, dir, draggable, dropzone, disabled, enctype, hidden, height, id, inputmode, label, lang, list, max, maxlength, method, min, minlength, multiple, name, novalidate, pattern, placeholder, readonly, required, rows, selected, selectionDirection, selectionEnd, selectionStart, size, spellcheck, src, step, style, tabindex, text, title, translate, type, value, width, wrap
-         }
-         validation {
-            showRules = alphabetic, alphanumeric, between, date, digit, email, equals, fileallowedtypes, filemaximumsize, fileminimumsize, float, greaterthan, inarray, integer, ip, length, lessthan, regexp, required, uri
-            rules {
-               alphabetic {
-                  showProperties = message, error, showMessage, allowWhiteSpace
-               }
-               alphanumeric {
-                  showProperties = message, error, showMessage, allowWhiteSpace
-               }
-               between {
-                  showProperties = message, error, showMessage, minimum, maximum, inclusive
-               }
-               date {
-                  showProperties = message, error, showMessage, format
-               }
-               digit {
-                  showProperties = message, error, showMessage
-               }
-               email {
-                  showProperties = message, error, showMessage
-               }
-               equals {
-                  showProperties = message, error, showMessage, field
-               }
-               fileallowedtypes {
-                  showProperties = message, error, showMessage, types
-               }
-               filemaximumsize {
-                  showProperties = message, error, showMessage, maximum
-               }
-               fileminimumsize {
-                  showProperties = message, error, showMessage, minimum
-               }
-               float {
-                  showProperties = message, error, showMessage
-               }
-               greaterthan {
-                  showProperties = message, error, showMessage, minimum
-               }
-               inarray {
-                  showProperties = message, error, showMessage, array, strict
-               }
-               integer {
-                  showProperties = message, error, showMessage
-               }
-               ip {
-                  showProperties = message, error, showMessage
-               }
-               length {
-                  showProperties = message, error, showMessage, minimum, maximum
-               }
-               lessthan {
-                  showProperties = message, error, showMessage, maximum
-               }
-               regexp {
-                  showProperties = message, error, showMessage, expression
-               }
-               required {
-                  showProperties = message, error, showMessage
-               }
-               uri {
-                  showProperties = message, error, showMessage
-               }
-            }
-         }
-         filtering {
-            showFilters = alphabetic, alphanumeric, currency, digit, integer, lowercase, regexp, stripnewlines, titlecase, trim, uppercase
-            filters {
-               alphabetic {
-                  showProperties = allowWhiteSpace
-               }
-               alphanumeric {
-                  showProperties = allowWhiteSpace
-               }
-               currency {
-                  showProperties = decimalPoint, thousandSeparator
-               }
-               digit {
-                  showProperties =
-               }
-               integer {
-                  showProperties =
-               }
-               lowercase {
-                  showProperties =
-               }
-               regexp {
-                  showProperties = expression
-               }
-               titlecase {
-                  showProperties =
-               }
-               trim {
-                  showProperties = characterList
-               }
-               uppercase {
-                  showProperties =
-               }
-            }
-         }
-      }
-  }
-
diff --git a/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/ShowTabs/Index.rst b/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/ShowTabs/Index.rst
deleted file mode 100644
index 667d2e35641fffc06cf0f37d04e6ab0746a34aee..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Administration/WizardSettings/DefaultsReference/ShowTabs/Index.rst
+++ /dev/null
@@ -1,75 +0,0 @@
-.. include:: ../../../../Includes.txt
-
-
-.. _wizard-settings-defaults-showtabs:
-
-========
-showTabs
-========
-
-(:ts:`mod.wizards.form.defaults.showTabs`)
-
-The configuration "showTabs" defines the outermost tabs on the left
-side of the form wizard.
-
-.. figure:: ../../../../Images/FormCreationWizardShowTabs.png
-    :alt: The form wizard with the main tabs.
-
-:aspect:`Property:`
-   showTabs
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Comma-separated list of the tabs that will be shown in the wizard.
-
-:aspect:`Default:`
-    elements, options, form
-
-
-.. _wizard-settings-defaults-tabs:
-
-tabs
-====
-
-(:ts:`mod.wizards.form.defaults.tabs`)
-
-Each of the 3 tabs can be further customized.
-
-:aspect:`Property:`
-    tabs
-
-:aspect:`Data type:`
-    [array of objects]
-
-    ->tabs.[tabName]
-
-:aspect:`Description:`
-    Configuration for each tab.
-
-
-Example
-=======
-
-.. code-block:: typoscript
-
-  mod.wizards {
-    form {
-      defaults {
-        showTabs = elements, options, form
-        tabs {
-          elements {
-            ...
-          }
-          options {
-            ...
-          }
-          form {
-            ...
-          }
-        }
-      }
-    }
-  }
-
diff --git a/typo3/sysext/form/Documentation/Administration/WizardSettings/ElementsReference/Index.rst b/typo3/sysext/form/Documentation/Administration/WizardSettings/ElementsReference/Index.rst
deleted file mode 100644
index ba46630a4e4a74431dd17df1da07a472c9d189a9..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Administration/WizardSettings/ElementsReference/Index.rst
+++ /dev/null
@@ -1,41 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _wizard-settings-elements:
-
-==================
-Elements reference
-==================
-
-Overrule the default settings of the :ref:`option <wizard-settings-defaults-options-tab>`
-tab for specific element types.
-
-In the left "settings" part there is a tab called "Options". The contents
-of this tab will adapt itself to the selected element type in the form.
-If no elements configuration exists, the default settings will be used.
-
-
-.. _overriding-element-settings:
-
-Overriding element settings
-===========================
-
-It is possible to override the default option tab settings for each
-element individually. This is done by using the same configuration as
-in :ts:`mod.wizards.form.defaults.tabs.options`, but using this
-configuration in :ts:`mod.wizards.form.elements.[elementName]`.
-
-The example below will hide all the accordions within the option tab for
-a text field (TEXTLINE element), except the filters:
-
-.. code-block:: typoscript
-
-   mod.wizards.form.elements {
-     textline {
-       showAccordions = filters
-     }
-   }
-
-By using this setting you can show or hide accordions, attributes,
-validation rules or filters, for each and every individual element.
-
diff --git a/typo3/sysext/form/Documentation/Administration/WizardSettings/Index.rst b/typo3/sysext/form/Documentation/Administration/WizardSettings/Index.rst
deleted file mode 100644
index 403d263bbeeaf65c074470d12c2b600e47a51da0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Administration/WizardSettings/Index.rst
+++ /dev/null
@@ -1,25 +0,0 @@
-.. include:: ../../Includes.txt
-
-
-.. _wizard-settings:
-
-===============
-Wizard settings
-===============
-
-The wizard basically consists of two parts on the screen, the left
-"settings" part and the right "form" part. With TSconfig settings it
-is possible to configure the contents of the left "settings" part. The
-integrator can remove tabs, accordions or a specific setting for a single
-type of form element, or for all element types at once.
-
-The basic configuration has two settings: **defaults** and **elements**.
-
-.. toctree::
-    :maxdepth: 5
-    :titlesonly:
-    :glob:
-
-    DefaultsReference/Index
-    ElementsReference/Index
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Filters/Alphabetic/Index.rst b/typo3/sysext/form/Documentation/Configuration/Filters/Alphabetic/Index.rst
deleted file mode 100644
index fe954f8816d8c908b55e98962d9796fe1f064512..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Filters/Alphabetic/Index.rst
+++ /dev/null
@@ -1,33 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-filters-alphabetic:
-
-==========
-alphabetic
-==========
-
-Removes all characters which are not in the range a-z or A-Z. With the
-setting allowWhiteSpace, spaces are allowed as well.
-
-
-.. _reference-filters-alphabetic-allowwhitespace:
-
-allowWhiteSpace
-===============
-
-:aspect:`Property:`
-    allowWhiteSpace
-
-:aspect:`Data type:`
-    boolean
-
-:aspect:`Description:`
-    If allowWhiteSpace = 1, whitespace is allowed in front of, after or
-    between the characters.
-
-:aspect:`Default:`
-    0
-
-[tsref:(cObject).FORM->filters.alphabetic]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Filters/Alphanumeric/Index.rst b/typo3/sysext/form/Documentation/Configuration/Filters/Alphanumeric/Index.rst
deleted file mode 100644
index 437e71a2a8f2191e93ad316b10b53e74d1d135f7..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Filters/Alphanumeric/Index.rst
+++ /dev/null
@@ -1,33 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-filters-alphanumeric:
-
-============
-alphanumeric
-============
-
-Removes all characters which are not in the range a-z, A-Z or 0-9. With the
-setting allowWhiteSpace, spaces are allowed as well.
-
-
-.. _reference-filters-alphanumeric-allowwhitespace:
-
-allowWhiteSpace
-===============
-
-:aspect:`Property:`
-    allowWhiteSpace
-
-:aspect:`Data type:`
-    boolean
-
-:aspect:`Description:`
-    If allowWhiteSpace = 1, whitespace is allowed in front of, after or
-    between the characters.
-
-:aspect:`Default:`
-    0
-
-[tsref:(cObject).FORM->filters.alphanumeric]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Filters/Currency/Index.rst b/typo3/sysext/form/Documentation/Configuration/Filters/Currency/Index.rst
deleted file mode 100644
index 6e85c765e3c0c7a4db1535b6227651166f80fb28..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Filters/Currency/Index.rst
+++ /dev/null
@@ -1,71 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-filters-currency:
-
-========
-currency
-========
-
-Changes a number to a formatted version with two decimals. The decimals
-point and thousands separator are configurable.
-
-**Example**
-
-- Submitted data: 100000.99
-
-- Filtered: 100 000,99
-
-.. code-block:: typoscript
-
-  filters {
-    1 = currency
-    1 {
-      decimalPoint = ,
-      thousandSeparator = space
-    }
-  }
-
-
-.. _reference-filters-currency-decimalpoint:
-
-decimalPoint
-============
-
-:aspect:`Property:`
-    decimalPoint
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Value for the decimal point, mostly a dot '.' or a comma ','
-
-:aspect:`Default:`
-    .
-
-
-.. _reference-filters-currency-thousandseparator:
-
-thousandSeparator
-=================
-
-:aspect:`Property:`
-    thousandSeparator
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Value for the thousand separator.
-
-    Special values:
-
-    - **space** : Adds a space as thousand separator
-    - **none** : No thousand separator
-
-:aspect:`Default:`
-    ,
-
-[tsref:(cObject).FORM->filters.currency]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Filters/Digit/Index.rst b/typo3/sysext/form/Documentation/Configuration/Filters/Digit/Index.rst
deleted file mode 100644
index 8c3602ee48d5c91e313ed4966693c490e3f26f37..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Filters/Digit/Index.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-filters-digit:
-
-=====
-digit
-=====
-
-Removes all characters which are not in the range 0-9.
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Filters/Index.rst b/typo3/sysext/form/Documentation/Configuration/Filters/Index.rst
deleted file mode 100644
index 733579287f8eebf8f240caea7b8016a858a5faae..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Filters/Index.rst
+++ /dev/null
@@ -1,53 +0,0 @@
-.. include:: ../../Includes.txt
-
-
-.. _reference-filters:
-
-Filters
-=======
-
-Add filters to the FORM objects.
-
-It is possible to have multiple filters for one FORM object, but the filters
-have to be added one by one.
-
-The submitted data for this particular object will be filtered by the
-assigned filters in the given order. The filtered data will be shown to the
-visitor when there are errors in the form or on a confirmation page.
-Otherwise the filtered data will be send by mail to the receiver.
-
-.. toctree::
-    :maxdepth: 5
-    :titlesonly:
-    :glob:
-
-    Alphabetic/Index.rst
-    Alphanumeric/Index.rst
-    Currency/Index.rst
-    Digit/Index.rst
-    Integer/Index.rst
-    Lowercase/Index.rst
-    Regexp/Index.rst
-    Stripnewlines/Index.rst
-    Titlecase/Index.rst
-    Trim/Index.rst
-    Uppercase/Index.rst
-
-**Example**
-
-The example shown below applies two filters to a FORM object.
-
-- Submitted data: john doe3
-
-- Filtered: John Doe
-
-.. code-block:: typoscript
-
-  filters {
-    1 = alphabetic
-    1 {
-      allowWhiteSpace = 1
-    }
-    2 = titlecase
-  }
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Filters/Integer/Index.rst b/typo3/sysext/form/Documentation/Configuration/Filters/Integer/Index.rst
deleted file mode 100644
index a05461bab644adb07d48ea82d4dbcb2f83fea2f1..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Filters/Integer/Index.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-filters-integer:
-
-=======
-integer
-=======
-
-Integers can be specified in decimal (10-based), optionally preceded by a
-sign (- or +).
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Filters/Lowercase/Index.rst b/typo3/sysext/form/Documentation/Configuration/Filters/Lowercase/Index.rst
deleted file mode 100644
index ab78c2374bd956dad6507032afc08e1eb55c46cd..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Filters/Lowercase/Index.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-filters-lowercase:
-
-=========
-lowercase
-=========
-
-Returns the incoming value with all alphabetic characters converted to
-lowercase. Alphabetic is determined by the Unicode character properties.
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Filters/Regexp/Index.rst b/typo3/sysext/form/Documentation/Configuration/Filters/Regexp/Index.rst
deleted file mode 100644
index 2e2bf116940846cd76032d2c518d5e9e503e0b88..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Filters/Regexp/Index.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-filters-regexp:
-
-======
-regexp
-======
-
-Removes matches in the submitted data found by the defined pattern.
-
-
-.. _reference-filters-regexp-expression:
-
-expression
-==========
-
-:aspect:`Property:`
-    expression
-
-:aspect:`Data type:`
-    boolean
-
-:aspect:`Description:`
-    The pattern holding the characters which need to be deleted.
-
-[tsref:(cObject).FORM->filters.regexp]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Filters/Stripnewlines/Index.rst b/typo3/sysext/form/Documentation/Configuration/Filters/Stripnewlines/Index.rst
deleted file mode 100644
index 943570d5c315883739942ef3678f19c919e20ffb..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Filters/Stripnewlines/Index.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-filters-stripnewlines:
-
-=============
-stripnewlines
-=============
-
-Convenient for textareas. It removes new lines from the submitted value.
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Filters/Titlecase/Index.rst b/typo3/sysext/form/Documentation/Configuration/Filters/Titlecase/Index.rst
deleted file mode 100644
index 9f30a8b438d2a0b400cd6505e41be0f80970a0d8..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Filters/Titlecase/Index.rst
+++ /dev/null
@@ -1,24 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-filters-titlecase:
-
-=========
-titlecase
-=========
-
-Returns the incoming value with all alphabetic characters converted to title
-case. Alphabetic is determined by the Unicode character properties.
-
-**Example**
-
-- Submitted data: kasper skårhøj
-
-- Filtered: Kasper Skårhøj
-
-.. code-block:: typoscript
-
-  filters {
-    1 = titlecase
-  }
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Filters/Trim/Index.rst b/typo3/sysext/form/Documentation/Configuration/Filters/Trim/Index.rst
deleted file mode 100644
index 6b457f484bcf9cb9a8ca31904a58527c71478857..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Filters/Trim/Index.rst
+++ /dev/null
@@ -1,33 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-filters-trim:
-
-====
-trim
-====
-
-Strips characters from the beginning and the end of the submitted value
-according to the list of characters. If no character list is set, it will
-only trim an ordinary space, a tab, a new line, a carriage return, the
-NUL-byte and a vertical tab.
-
-
-.. _reference-filters-trim-characterlist:
-
-characterList
-=============
-
-:aspect:`Property:`
-    characterList
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    List of characters to be trimmed.
-
-    See the PHP-manual (trim) for the options of the charlist.
-
-[tsref:(cObject).FORM->filters.regexp]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Filters/Uppercase/Index.rst b/typo3/sysext/form/Documentation/Configuration/Filters/Uppercase/Index.rst
deleted file mode 100644
index b4e7276194d98e02db44965355606724dcd59b11..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Filters/Uppercase/Index.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-filters-uppercase:
-
-=========
-uppercase
-=========
-
-Returns the incoming value with all alphabetic characters converted to
-uppercase. Alphabetic is determined by the Unicode character properties.
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Index.rst b/typo3/sysext/form/Documentation/Configuration/Index.rst
deleted file mode 100644
index baeea5914b7a7b9653c3cfa7366d2b9ec7796f1a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Index.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-.. include:: ../Includes.txt
-
-
-.. _configuration:
-
-=============
-Configuration
-=============
-
-.. only:: html
-
-    .. tip::
-
-      Whenever there is a reference to anything named an "object" in this
-      section it is a reference to a "FORM object" and not the "cObjects"
-      unless it is clearly stated.
-
-.. toctree::
-    :maxdepth: 5
-    :titlesonly:
-    :glob:
-
-    Objects/Index
-    Layout/Index
-    Rules/Index
-    Filters/Index
-    Postprocessors/Index
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Layout/Index.rst b/typo3/sysext/form/Documentation/Configuration/Layout/Index.rst
deleted file mode 100644
index 92e5b74750b266f3e11c18dbbc12ba8e4719f265..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Layout/Index.rst
+++ /dev/null
@@ -1,69 +0,0 @@
-.. include:: ../../Includes.txt
-
-
-.. _reference-layout:
-
-======
-Layout
-======
-
-.. attention::
-
-    The form wizard (available in the TYPO3 backend) does not support the
-    complex layout mechanism described in this chapter. As soon as the
-    integrator has applied custom layout settings, the form wizard should
-    not be used anymore. When opening the customized form inside the form
-    wizard and hitting the "Save" button, all custom layout settings will be
-    lost.
-
-Using layout allows the integrator to change the default visual appearance
-of the FORM objects.
-
-The FORM consists of FORM objects, which have their own layout each. The
-layout of these objects can be changed for the whole form, for a specific
-view or just for a particular object.
-
-By default, the overall markup is based on ordered lists with list elements
-in it, to have a proper layout framework which is also accessible for people
-with disabilities.
-
-Some objects are considered being container objects, as they have child
-objects. These objects are FORM, FIELDSET, CHECKBOXGROUP and RADIOGROUP. To
-have a proper markup for these objects, nested ordered lists are used.
-
-**Example**
-
-.. code-block:: html
-
-  <form>
-    <ol>
-      <li>
-        <fieldset>
-          <ol>
-            <li>
-              <input />
-            </li>
-          </ol>
-        </fieldset>
-      </li>
-      <li>
-        <input />
-      </li>
-    </ol>
-  </form>
-
-It could be stated that SELECT and OPTGROUP elements are container objects
-as well, and actually this is correct. They also contain child objects. But
-these objects are not allowed to use the above mentioned markup.
-
-There are 3 ways to modify the layout:
-
-.. toctree::
-    :maxdepth: 5
-    :titlesonly:
-    :glob:
-
-    LayoutWholeForm/Index
-    LayoutViewSpecific/Index
-    LayoutObjectSpecific/Index
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Layout/LayoutObjectSpecific/Index.rst b/typo3/sysext/form/Documentation/Configuration/Layout/LayoutObjectSpecific/Index.rst
deleted file mode 100644
index 84e51101aedbd4c2d189f2e94b41ec4c46901519..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Layout/LayoutObjectSpecific/Index.rst
+++ /dev/null
@@ -1,29 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _change-layout-individual-form:
-
-===============================================
-Change the layout for an individual FORM object
-===============================================
-
-It is also possible to override the layout setting of a particular object
-within the form, like a checkbox. The layout function within an object only
-accepts the markup, like the following one.
-
-.. code-block:: typoscript
-
-  tt_content.mailform.20 {
-    10 = CHECKBOX
-    10 {
-      label = I want to receive the monthly newsletter by email.
-      layout (
-        <input />
-        <label />
-      )
-    }
-  }
-
-The example shows how to switch the input field and the label, just for this
-particular checkbox.
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Layout/LayoutViewSpecific/Index.rst b/typo3/sysext/form/Documentation/Configuration/Layout/LayoutViewSpecific/Index.rst
deleted file mode 100644
index 30b70de679d638c00568301ce2cbf55c04f95995..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Layout/LayoutViewSpecific/Index.rst
+++ /dev/null
@@ -1,1592 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _change-layout-specific-view:
-
-=====================================
-Change the layout for a specific view
-=====================================
-
-.. contents::
-    :local:
-    :depth: 1
-
-
-.. _change-layout-specific-view-available-views:
-
-Available views
-===============
-
-There are 3 views available:
-
-form:
-  This view displays the form with its form fields which can be filled by
-  the user and submitted.
-
-confirmation:
-  If activated, this view shows a confirmation page which has to be
-  confirmed by the user.
-
-postProcessor:
-  The mail postProcessor has its own view for rendering the mail which is
-  sent to the receiver.
-
-It is not recommended to change the layout of a FORM object for all views.
-For example when customizing the TEXTLINE object the integrator will get
-strange results based on the following example:
-
-.. code-block:: typoscript
-
-  tt_content.mailform.20 {
-    layout {
-      textline (
-        <div class="form-group">
-          <div class="col-sm-3 control-label">
-            <label />
-          </div>
-          <div class="col-sm-5">
-            <input class="form-control" />
-          </div>
-        </div>
-      )
-    }
-  }
-
-The setup shown above changes the appearance of all TEXTLINE objects for all
-views. That is, the user will get a confirmation page and a mail with
-broken/ senseless input fields instead of the user data.
-
-In order to only change the TEXTLINE object specific to all of the 3 views,
-the following code could be applied.
-
-.. code-block:: typoscript
-
-  tt_content.mailform.20 {
-    # customize form view
-    form {
-      layout {
-        textline (
-          <div class="form-group">
-            <div class="col-sm-3 control-label">
-              <label />
-            </div>
-            <div class="col-sm-5">
-              <input class="form-control" />
-            </div>
-          </div>
-        )
-      }
-    }
-
-    # customize confirmation view
-    confirmation {
-      layout {
-        textline (
-          <div class="form-group">
-            <div class="col-sm-3">
-              <strong><label /></strong>
-            </div>
-            <div class="col-sm-5">
-              <inputvalue />
-            </div>
-          </div>
-        )
-      }
-    }
-
-    # customize postProcessor/ mail
-    postProcessor {
-      layout {
-        textline (
-          <td colspan="2">
-            <div class="textline"><inputvalue /></div>
-          </td>
-        )
-      }
-    }
-  }
-
-
-.. _change-layout-specific-view-properties:
-
-Properties and defaults
-=======================
-
-If the integrator does not define any :ts:`.layout` setting the default
-layout defined in the PHP classes will be used.
-
-The following list shows all available elements within all the different
-views including their corresponding default layouts.
-
-.. contents::
-    :local:
-    :depth: 1
-
-
-.. _reference-layout-form:
-
-form
-^^^^
-
-:aspect:`Property:`
-    form
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-
-:aspect:`Description:`
-    Layout of the FORM object/ outer wrap.
-
-    The <containerwrap /> tag will be substituted by the outer container
-    wrap and includes all child elements.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <form>
-        <containerWrap />
-      </form>
-
-
-.. _reference-layout-confirmation:
-
-confirmation
-^^^^^^^^^^^^
-
-:aspect:`Property:`
-    confirmation
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - confirmation
-
-:aspect:`Description:`
-    Layout of the outer wrap.
-
-    The <containerwrap /> tag will be substituted by the outer container
-    wrap and includes all child elements.
-
-:aspect:`Default:`
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <containerWrap />
-
-
-.. _reference-layout-html:
-
-html
-^^^^
-
-:aspect:`Property:`
-    html
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - postProcessor
-
-:aspect:`Description:`
-    Layout of the outer wrap.
-
-    The <containerwrap /> tag will be substituted by the outer container
-    wrap and includes all child elements.
-
-:aspect:`Default:`
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <html>
-        <head>
-          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-        </head>
-        <body>
-          <table cellspacing="0">
-            <containerWrap />
-          </table>
-        </body>
-      </html>
-
-
-.. _reference-layout-containerwrap:
-
-containerWrap
-^^^^^^^^^^^^^
-
-:aspect:`Property:`
-    containerWrap
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Inner wrap for container objects.
-
-    The <elements /> tag will be substituted with all the child elements,
-    including their element wraps.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <ol>
-        <elements />
-      </ol>
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <ol>
-        <elements />
-      </ol>
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <tbody>
-        <elements />
-      </tbody>
-
-
-.. _reference-layout-elementwrap:
-
-elementWrap
-^^^^^^^^^^^
-
-:aspect:`Property:`
-    elementWrap
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Outer wrap for regular objects.
-
-    The <element /> tag will be substituted with the child element.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <li>
-        <element />
-      </li>
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <li>
-        <element />
-      </li>
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <tr>
-        <element />
-      </tr>
-
-
-.. _reference-layout-label:
-
-label
-^^^^^
-
-:aspect:`Property:`
-    label
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Layout for the labels.
-
-    The <labelvalue /> tag will be substituted with the label text.
-
-    If available, the <mandatory /> tag will be substituted with the
-    validation rule message, styled by its own layout.
-
-    If available, the <error /> tag will be substituted with the error
-    message from the validation rule when the submitted value is not valid.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <label>
-        <labelvalue />
-        <mandatory />
-        <error />
-      </label>
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <label>
-        <labelvalue />
-      </label>
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <em>
-        <labelvalue />
-      </em>
-
-
-.. _reference-layout-mandatory:
-
-mandatory
-^^^^^^^^^
-
-:aspect:`Property:`
-    mandatory
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-
-:aspect:`Description:`
-    Layout for the validation rule message to describe the rule.
-
-    The <mandatoryvalue /> tag will be substituted with the validation rule
-    message.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <em>
-        <mandatoryvalue />
-      </em>
-
-
-.. _reference-layout-error:
-
-error
-^^^^^
-
-:aspect:`Property:`
-    error
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-
-:aspect:`Description:`
-    Layout for the validation rule error message when the submitted data
-    does not validate.
-
-    The <errorvalue /> tag will be substituted with the validation rule
-    error message.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <strong>
-        <errorvalue />
-      </strong>
-
-
-.. _reference-layout-legend:
-
-legend
-^^^^^^
-
-:aspect:`Property:`
-    legend
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Layout for the legend.
-
-    The <legendvalue /> tag will be substituted with the legend text.
-
-    If available, the <mandatory /> tag will be substituted with the
-    validation rule message, styled by its own layout.
-
-    If available, the <error /> tag will be substituted with the error
-    message from the validation rule when the submitted value is not valid.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <legend>
-        <legendvalue />
-        <mandatory />
-        <error />
-      </legend>
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <legend>
-        <legendvalue />
-      </legend>
-
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <thead>
-        <tr>
-          <th colspan="2" align="left">
-            <legendvalue />
-          </th>
-        </tr>
-      </thead>
-
-
-.. _reference-layout-button:
-
-button
-^^^^^^
-
-:aspect:`Property:`
-    button
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-
-:aspect:`Description:`
-    Layout for the BUTTON object.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <label />
-      <input />
-
-
-.. _reference-layout-checkbox:
-
-checkbox
-^^^^^^^^
-
-:aspect:`Property:`
-    checkbox
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Layout for the CHECKBOX object.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <label />
-      <input />
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <label />
-      <inputvalue />
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <td style="width: 200px;">
-        <label />
-      </td>
-      <td>
-        <inputvalue />
-      </td>
-
-
-.. _reference-layout-checkboxgroup:
-
-checkboxgroup
-^^^^^^^^^^^^^
-
-:aspect:`Property:`
-    checkboxgroup
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Layout for the CHECKBOXGROUP object.
-
-    The <containerwrap /> tag will be substituted by the outer container
-    wrap and includes all child elements.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <fieldset>
-        <legend />
-        <containerWrap />
-      </fieldset>
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <fieldset>
-        <legend />
-        <containerWrap />
-      </fieldset>
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <td colspan="2">
-        <table cellspacing="0" style="padding-left: 20px; margin-bottom: 20px;">
-          <legend />
-          <containerWrap />
-        </table>
-      </td>
-
-
-.. _reference-layout-fieldset:
-
-fieldset
-^^^^^^^^
-
-:aspect:`Property:`
-    fieldset
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Layout for the FIELDSET object.
-
-    The <containerwrap /> tag will be substituted by the outer container
-    wrap and includes all child elements.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <fieldset>
-        <legend />
-        <containerWrap />
-      </fieldset>
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <fieldset>
-        <legend />
-        <containerWrap />
-      </fieldset>
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <td colspan="2">
-        <table cellspacing="0" style="padding-left: 20px; margin-bottom: 20px;">
-          <legend />
-          <containerWrap />
-        </table>
-      </td>
-
-
-.. _reference-layout-fileupload:
-
-fileupload
-^^^^^^^^^^
-
-:aspect:`Property:`
-    fileupload
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Layout for the FILEUPLOAD object.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <label />
-      <input />
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <label />
-      <inputvalue />
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <td style="width: 200px;">
-        <label />
-      </td>
-      <td>
-        <inputvalue />
-      </td>
-
-
-.. _reference-layout-hidden:
-
-hidden
-^^^^^^
-
-:aspect:`Property:`
-    hidden
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - postProcessor
-
-:aspect:`Description:`
-    Layout for the HIDDEN object.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <input />
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <td style="width: 200px;">
-        <em>
-          <label />
-        </em>
-      </td>
-      <td>
-        <inputvalue />
-      </td>
-
-
-.. _reference-layout-optgroup:
-
-optgroup
-^^^^^^^^
-
-:aspect:`Property:`
-    optgroup
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Layout for the OPTGROUP object.
-
-    The <elements /> tag will be substituted with all the child elements,
-    which actually can only be OPTION objects.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <optgroup>
-        <elements />
-      </optgroup>
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <elements />
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <elements />
-
-
-.. _reference-layout-option:
-
-option
-^^^^^^
-
-:aspect:`Property:`
-    option
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Layout for the OPTION object.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <option />
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <inputvalue />
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <div>
-        <inputvalue />
-      </div>
-
-
-.. _reference-layout-password:
-
-password
-^^^^^^^^
-
-:aspect:`Property:`
-    password
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-
-:aspect:`Description:`
-    Layout for the PASSWORD object.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <label />
-      <input />
-
-
-.. _reference-layout-radio:
-
-radio
-^^^^^
-
-:aspect:`Property:`
-    radio
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Layout for the RADIO object.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <label />
-      <input />
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <label />
-      <inputvalue />
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <td style="width: 200px;">
-        <label />
-      </td>
-      <td>
-        <inputvalue />
-      </td>
-
-
-.. _reference-layout-radiogroup:
-
-radiogroup
-^^^^^^^^^^
-
-:aspect:`Property:`
-    radiogroup
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Layout for the RADIOGROUP object.
-
-    The <containerwrap /> tag will be substituted by the outer container
-    wrap and includes all child elements.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <fieldset>
-        <legend />
-        <containerWrap />
-      </fieldset>
-
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <fieldset>
-        <legend />
-        <containerWrap />
-      </fieldset>
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <td colspan="2">
-        <table cellspacing="0" style="padding-left: 20px; margin-bottom: 20px;">
-          <legend />
-          <containerWrap />
-        </table>
-      </td>
-
-
-.. _reference-layout-reset:
-
-reset
-^^^^^
-
-:aspect:`Property:`
-    reset
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-
-:aspect:`Description:`
-    Layout for the RESET object.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <label />
-      <input />
-
-
-.. _reference-layout-select:
-
-select
-^^^^^^
-
-:aspect:`Property:`
-    select
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Layout for the SELECT object.
-
-    The <elements /> tag will be substituted with all the child elements,
-    which only can be OPTGROUP or OPTION objects.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <label />
-      <select>
-         <elements />
-      </select>
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <label />
-      <ol>
-         <elements />
-      </ol>
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <td style="width: 200px;">
-        <label />
-      </td>
-      <td>
-        <elements />
-      </td>
-
-
-.. _reference-layout-submit:
-
-submit
-^^^^^^
-
-:aspect:`Property:`
-    submit
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-
-:aspect:`Description:`
-    Layout for the SUBMIT object.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <label />
-      <input />
-
-
-.. _reference-layout-textarea:
-
-textarea
-^^^^^^^^
-
-:aspect:`Property:`
-    textarea
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Layout for the TEXTAREA object.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <label />
-      <textarea />
-
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <label />
-      <inputvalue />
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <td style="width: 200px;" valign="top">
-          <label />
-      </td>
-      <td>
-          <inputvalue />
-      </td>
-
-
-.. _reference-layout-textblock:
-
-textblock
-^^^^^^^^^
-
-:aspect:`Property:`
-    textblock
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-
-:aspect:`Description:`
-    Layout for the TEXTBLOCK object.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <textblock />
-
-
-.. _reference-layout-textline:
-
-textline
-^^^^^^^^
-
-:aspect:`Property:`
-    textline
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Available in views:`
-    - form
-    - confirmation
-    - postProcessor
-
-:aspect:`Description:`
-    Layout for the TEXTLINE object.
-
-:aspect:`Default:`
-    Default layout **form view**:
-
-    .. code-block:: html
-
-      <label />
-      <input />
-
-    Default layout **confirmation view**:
-
-    .. code-block:: html
-
-      <label />
-      <inputvalue />
-
-    Default layout **postProcessor view**:
-
-    .. code-block:: html
-
-      <td style="width: 200px;">
-        <label />
-      </td>
-      <td>
-        <inputvalue />
-      </td>
-
-
-.. _change-layout-specific-view-example:
-
-Example showing all .layout properties and defaults
-===================================================
-
-The code snippets below shows all available settings across all views
-including their default layout.
-
-.. code-block:: typoscript
-
-  tt_content.mailform.20 {
-    # ###
-    # form view
-    # ####
-
-    form {
-      layout {
-        form (
-          <form>
-            <containerWrap />
-          </form>
-        )
-
-        containerWrap (
-          <ol>
-            <elements />
-          </ol>
-        )
-
-        elementWrap (
-          <li>
-            <element />
-          </li>
-        )
-
-        label (
-          <label>
-            <labelvalue />
-            <mandatory />
-            <error />
-          </label>
-        )
-
-        mandatory (
-          <em>
-            <mandatoryvalue />
-          </em>
-        )
-
-        error (
-          <strong>
-            <errorvalue />
-          </strong>
-        )
-
-        legend (
-          <legend>
-            <legendvalue />
-            <mandatory />
-            <error />
-          </legend>
-        )
-
-        button (
-          <label />
-          <input />
-        )
-
-        checkbox (
-          <label />
-          <input />
-        )
-
-        checkboxgroup (
-          <fieldset>
-            <legend />
-            <containerWrap />
-          </fieldset>
-        )
-        fieldset (
-            <fieldset>
-                <legend />
-                <containerWrap />
-            </fieldset>
-        )
-
-        fileupload (
-          <label />
-          <input />
-        )
-
-        hidden (
-          <input />
-        )
-
-        optgroup (
-          <optgroup>
-            <elements />
-          </optgroup>
-        )
-
-        option (
-          <option />
-        )
-
-        password (
-          <label />
-          <input />
-        )
-
-        radio (
-          <label />
-          <input />
-        )
-
-        radiogroup (
-          <fieldset>
-            <legend />
-            <containerWrap />
-          </fieldset>
-        )
-
-        reset (
-          <label />
-          <input />
-        )
-
-        select (
-          <label />
-          <select>
-            <elements />
-          </select>
-        )
-
-        submit (
-          <label />
-          <input />
-        )
-
-        textarea (
-          <label />
-          <textarea />
-        )
-
-        textblock (
-          <textblock />
-        )
-
-        textline (
-          <label />
-          <input />
-        )
-      }
-    }
-
-    # ###
-    # confirmation view
-    # ###
-
-    confirmation {
-      layout {
-        confirmation (
-          <containerWrap />
-        )
-
-        containerWrap (
-          <ol>
-            <elements />
-          </ol>
-        )
-
-        elementWrap (
-          <li>
-            <element />
-          </li>
-        )
-
-        label (
-          <label>
-            <labelvalue />
-          </label>
-        )
-
-        legend (
-          <legend>
-            <legendvalue />
-          </legend>
-        )
-
-        checkbox (
-          <label />
-          <inputvalue />
-        )
-
-        checkboxgroup (
-          <fieldset>
-            <legend />
-            <containerWrap />
-          </fieldset>
-        )
-
-        fieldset (
-          <fieldset>
-            <legend />
-            <containerWrap />
-          </fieldset>
-        )
-
-        fileupload (
-          <label />
-          <inputvalue />
-        )
-
-        optgroup (
-          <elements />
-        )
-
-        option (
-          <inputvalue />
-        )
-
-        radio (
-          <label />
-          <inputvalue />
-        )
-
-        radiogroup (
-          <fieldset>
-            <legend />
-            <containerWrap />
-          </fieldset>
-        )
-
-        select (
-          <label />
-          <ol>
-            <elements />
-          </ol>
-        )
-
-        textarea (
-          <label />
-          <inputvalue />
-        )
-
-        textline (
-          <label />
-          <inputvalue />
-        )
-      }
-    }
-
-    # ###
-    # postProcesso view
-    # ###
-
-    postProcessor {
-      layout {
-        html (
-          <html>
-            <head>
-              <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-            </head>
-            <body>
-              <table cellspacing="0">
-                <containerWrap />
-              </table>
-            </body>
-          </html>
-        )
-
-        containerWrap (
-          <tbody>
-            <elements />
-          </tbody>
-        )
-
-        elementWrap (
-          <tr>
-            <element />
-          </tr>
-        )
-
-        label (
-          <em>
-            <labelvalue />
-          </em>
-        )
-
-        legend (
-          <thead>
-            <tr>
-              <th colspan="2" align="left">
-                <legendvalue />
-              </th>
-            </tr>
-          </thead>
-        )
-
-        checkbox (
-          <td style="width: 200px;">
-            <label />
-          </td>
-          <td>
-            <inputvalue />
-          </td>
-        )
-
-        checkboxgroup (
-          <td colspan="2">
-            <table cellspacing="0" style="padding-left: 20px; margin-bottom: 20px;">
-              <legend />
-              <containerWrap />
-            </table>
-          </td>
-        )
-
-        fieldset (
-          <td colspan="2">
-            <table cellspacing="0" style="padding-left: 20px; margin-bottom: 20px;">
-              <legend />
-              <containerWrap />
-            </table>
-          </td>
-        )
-
-        fileupload (
-          <td style="width: 200px;">
-            <label />
-          </td>
-          <td>
-            <inputvalue />
-          </td>
-        )
-
-        hidden (
-          <td style="width: 200px;">
-            <em>
-              <label />
-            </em>
-          </td>
-          <td>
-            <inputvalue />
-          </td>
-        )
-
-        optgroup (
-          <elements />
-        )
-
-        option (
-          <div>
-            <inputvalue />
-          </div>
-        )
-
-        radio (
-          <td style="width: 200px;">
-            <label />
-          </td>
-          <td>
-            <inputvalue />
-          </td>
-        )
-
-        radiogroup (
-          <td colspan="2">
-            <table cellspacing="0" style="padding-left: 20px; margin-bottom: 20px;">
-              <legend />
-              <containerWrap />
-            </table>
-          </td>
-        )
-
-        select (
-          <td style="width: 200px;">
-            <label />
-          </td>
-          <td>
-            <elements />
-          </td>
-        )
-
-        textarea (
-          <td style="width: 200px;" valign="top">
-            <label />
-          </td>
-          <td>
-            <inputvalue />
-          </td>
-        )
-
-        textline (
-          <td style="width: 200px;">
-            <label />
-          </td>
-          <td>
-            <inputvalue />
-          </td>
-        )
-      }
-    }
-  }
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Layout/LayoutWholeForm/Index.rst b/typo3/sysext/form/Documentation/Configuration/Layout/LayoutWholeForm/Index.rst
deleted file mode 100644
index 5ee35260eed02084aa36516ca9fb26035c133e1c..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Layout/LayoutWholeForm/Index.rst
+++ /dev/null
@@ -1,46 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _change-layout-of-whole-form:
-
-===================================
-Change the layout of the whole form
-===================================
-
-.. attention::
-
-    It is not recommended to change the layout globally for the whole form.
-    Unfortunately, using view specific layout settings did not work for a
-    long time and is now widely used by integrators.
-
-    There are several reasons for not to use global layout settings:
-
-    - Some objects cannot be changed globally.
-    - Changing some objects will cause problems which lead to failures in
-      the processing. The code will die with PHP errors.
-    - Quite often it does not make sense to do these changes globally.
-
-    Instead change the layout for a :ref:`specific view <change-layout-specific-view>`!
-
-Apart from the above mentioned problems one could change the layout globally
-using the following TypoScript setup. Using :ts:`tt_content.mailform.20`
-registers the chances for all forms of the below the page tree. If one wants
-to change the layout only for a specific form, a TypoScript library could be
-build as shown :ref:`here <reference-form-example>`.
-
-.. code-block:: typoscript
-
-  tt_content.mailform.20 {
-    layout {
-      # changing the layout of the form object globally
-      form (
-        <form class="form-class">
-          <containerWrap />
-        </form>
-      )
-    }
-  }
-
-As one can see, an (X)HTML kind of markup is used. Actually it is XML, with
-some extra tags like the :ts:`containerWrap`.
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Button/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Button/Index.rst
deleted file mode 100644
index 06eec34f78287bf71fe22940ebccefe7730107d3..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Button/Index.rst
+++ /dev/null
@@ -1,158 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-button:
-
-======
-BUTTON
-======
-
-Creates a push button. User agents should use the value of the value
-attribute as the button's label.
-
-Push buttons have no default behavior. Each push button may have
-client-side scripts associated with the element's event attributes.
-When an event occurs (e.g., the user presses the button, releases it,
-etc.), the associated script is triggered.
-
-
-.. _reference-button-accesskey:
-
-accesskey
-=========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-accesskey`.
-
-
-.. _reference-button-alt:
-
-alt
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-alt`.
-
-
-.. _reference-button-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-button-dir:
-
-dir
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-dir`.
-
-
-.. _reference-button-disabled:
-
-disabled
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-disabled`.
-
-
-.. _reference-button-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-id`.
-
-
-.. _reference-button-label:
-
-label
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-label`.
-
-
-.. _reference-button-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-lang`.
-
-
-.. _reference-button-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-button`
-    specific information.
-
-
-.. _reference-button-name:
-
-name
-====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-name`.
-
-
-.. _reference-button-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-style`.
-
-
-.. _reference-button-tabindex:
-
-tabindex
-========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-tabindex`.
-
-
-.. _reference-button-title:
-
-title
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-title`.
-
-
-.. _reference-button-type:
-
-type
-====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-type`.
-
-:aspect:`Default:`
-    button
-
-
-.. _reference-button-value:
-
-value
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-value`.
-
-[tsref:(cObject).FORM.FormObject.BUTTON]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Checkbox/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Checkbox/Index.rst
deleted file mode 100644
index 3de4a636112d3498123350ee3b9a33654f1e8380..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Checkbox/Index.rst
+++ /dev/null
@@ -1,169 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-checkbox:
-
-========
-CHECKBOX
-========
-
-Creates a checkbox.
-
-Checkboxes are on/off switches that may be toggled by the user. A switch is
-"on" when the control element's checked attribute is set. When a form is
-submitted, only "on" checkbox controls can become successful.
-
-Several checkboxes in a form may share the same control name. Thus, for
-example, checkboxes allow users to select several values for the same
-property. A CHECKBOX object only displays one checkbox in the form.
-
-
-.. _reference-checkbox-accesskey:
-
-accesskey
-=========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-accesskey`.
-
-
-.. _reference-checkbox-alt:
-
-alt
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-alt`.
-
-
-.. _reference-checkbox-checked:
-
-checked
-=======
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-checked`.
-
-
-.. _reference-checkbox-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-checkbox-dir:
-
-dir
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-dir`.
-
-
-.. _reference-checkbox-disabled:
-
-disabled
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-disabled`.
-
-
-.. _reference-checkbox-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-id`.
-
-
-.. _reference-checkbox-label:
-
-label
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-label`.
-
-
-.. _reference-checkbox-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-lang`.
-
-
-.. _reference-checkbox-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-checkbox`
-    specific information.
-
-
-.. _reference-checkbox-name:
-
-name
-====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-name`.
-
-
-.. _reference-checkbox-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-style`.
-
-
-.. _reference-checkbox-tabindex:
-
-tabindex
-========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-tabindex`.
-
-
-.. _reference-checkbox-title:
-
-title
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-title`.
-
-
-.. _reference-checkbox-type:
-
-type
-====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-type`.
-
-:aspect:`Default:`
-    checkbox
-
-
-.. _reference-checkbox-value:
-
-value
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-value`.
-
-[tsref:(cObject).FORM.FormObject.CHECKBOX]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Fieldset/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Fieldset/Index.rst
deleted file mode 100644
index 7884cca96e626a10d633b4816242d31581c26c01..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Fieldset/Index.rst
+++ /dev/null
@@ -1,96 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-fieldset:
-
-========
-FIELDSET
-========
-
-The FIELDSET element allows authors to group thematically related controls
-and labels. Grouping controls makes it easier for users to understand the
-purpose while simultaneously facilitating tabbing navigation for visual user
-agents and speech navigation for speech-oriented user agents. The proper use
-of this element makes documents more accessible.
-
-
-.. _reference-fieldset-1-2-3-4:
-
-1, 2, 3, 4 ...
-==============
-
-:aspect:`Property:`
-    1, 2, 3, 4 ...
-
-:aspect:`Data type:`
-    [array of FORM objects]
-
-:aspect:`Description:`
-    FORM objects that are part of the FIELDSET.
-
-
-.. _reference-fieldset-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-fieldset-dir:
-
-dir
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-dir`.
-
-
-.. _reference-fieldset-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-lang`.
-
-
-.. _reference-fieldset-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-label`.
-
-
-.. _reference-fieldset-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-fieldset`
-    specific information.
-
-
-.. _reference-fieldset-legend:
-
-legend
-======
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-legend`.
-
-
-.. _reference-fieldset-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-style`.
-
-[tsref:(cObject).FORM.FormObject.FIELDSET]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Fileupload/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Fileupload/Index.rst
deleted file mode 100644
index d7490ed27dde5834a5912af72cf6ca4ea9f44061..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Fileupload/Index.rst
+++ /dev/null
@@ -1,156 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-fileupload:
-
-==========
-FILEUPLOAD
-==========
-
-Creates a file select control. User agents may use the value of the value
-attribute as the initial file name.
-
-This control type allows the user to select files so that their contents may
-be submitted with a form.
-
-
-.. _reference-fileupload-accesskey:
-
-accesskey
-=========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-accesskey`.
-
-
-.. _reference-fileupload-alt:
-
-alt
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-alt`.
-
-
-.. _reference-fileupload-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-fileupload-dir:
-
-dir
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-dir`.
-
-
-.. _reference-fileupload-disabled:
-
-disabled
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-disabled`.
-
-
-.. _reference-fileupload-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-id`.
-
-
-.. _reference-fileupload-label:
-
-label
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-label`.
-
-
-.. _reference-fileupload-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-lang`.
-
-
-.. _reference-fileupload-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-fileupload`
-    specific information.
-
-
-.. _reference-fileupload-name:
-
-name
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-name`.
-
-
-.. _reference-fileupload-size:
-
-size
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-size`.
-
-
-.. _reference-fileupload-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-style`.
-
-
-.. _reference-fileupload-tabindex:
-
-tabindex
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-tabindex`.
-
-
-.. _reference-fileupload-title:
-
-title
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-title`.
-
-
-.. _reference-fileupload-type:
-
-type
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-type`.
-
-:aspect:`Default:`
-    file
-
-[tsref:(cObject).FORM.FormObject.FILEUPLOAD]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Form/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Form/Index.rst
deleted file mode 100644
index 928d05c5168831a8d1efcfc46dc867ce4bbd3a69..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Form/Index.rst
+++ /dev/null
@@ -1,313 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-form:
-
-====
-FORM
-====
-
-A form will always start with the FORM object. TYPO3 recognizes this object
-and sends all TypoScript data to the FORM extension.
-
-
-.. _reference-form-accept:
-
-accept
-======
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-accept`.
-
-
-.. _reference-form-accept-charset:
-
-accept-charset
-==============
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-accept-charset`.
-
-
-.. _reference-form-action:
-
-action
-======
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-action`.
-
-
-.. _reference-form-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-form-dir:
-
-dir
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-dir`.
-
-
-.. _reference-form-enctype:
-
-enctype
-=======
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-enctype`.
-
-
-.. _reference-form-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-id`.
-
-
-.. _reference-form-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-lang`.
-
-
-.. _reference-form-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-form`
-    specific information.
-
-
-.. _reference-form-method:
-
-method
-======
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-method`.
-
-
-.. _reference-form-name:
-
-name
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-name`.
-
-
-.. _reference-form-postprocessor:
-
-postProcessor
-=============
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-postProcessor`.
-
-
-.. _reference-form-prefix:
-
-prefix
-======
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-prefix`.
-
-
-.. _reference-form-rules:
-
-rules
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-rules`.
-
-
-.. _reference-form-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-style`.
-
-
-.. _reference-form-title:
-
-title
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-title`.
-
-
-[tsref:(cObject).FORM]
-
-.. _reference-form-example:
-
-Example
-=======
-
-This example shows a simple payment form. At the beginning the layout of the
-radio buttons is changed for the form view. The label and the input field
-are switched.
-
-The example builds a form as TypoScript library which can be assigned to a
-marker or used inside a fluid template. The defined layout settings are only
-valid within this TS library.
-
-.. code-block:: typoscript
-
-  lib.form = FORM
-  lib.form {
-    method = post
-
-    postProcessor {
-      # ...
-    }
-
-    form {
-      layout {
-        radio (
-          <input />
-          <label />
-        )
-      }
-    }
-
-    10 = FIELDSET
-    10 {
-      legend = Name
-
-      10 = SELECT
-      10 {
-        label = Title
-
-        10 = OPTION
-        10 {
-          data = Mr.
-          selected = 1
-        }
-
-        20 = OPTION
-        20 {
-          data = Mrs.
-        }
-
-        30 = OPTION
-        30 {
-          data = Ms.
-        }
-
-        40 = OPTION
-        40 {
-          data = Dr.
-        }
-
-        50 = OPTION
-        50 {
-          data = Viscount
-        }
-      }
-
-      20 = TEXTLINE
-      20 {
-        label = First name
-      }
-
-      30 = TEXTLINE
-      30 {
-        label = Last name
-      }
-    }
-
-    20 = FIELDSET
-    20 {
-      legend = Address
-
-      10 = TEXTLINE
-      10 {
-        label = Street
-      }
-
-      20 = TEXTLINE
-      20 {
-        label = City
-      }
-
-      30 = TEXTLINE
-      30 {
-        label = State
-      }
-
-      40 = TEXTLINE
-      40 {
-        label = ZIP code
-      }
-    }
-
-    30 = FIELDSET
-    30 {
-      legend = Payment details
-
-      10 = FIELDSET
-      10 {
-        legend = Credit card
-
-        10 = RADIO
-        10 {
-          label = American Express
-          name = creditcard
-        }
-
-        20 = RADIO
-        20 {
-          label = Mastercard
-          name = creditcard
-        }
-
-        30 = RADIO
-        30 {
-          label = Visa
-          name = creditcard
-        }
-
-        40 = RADIO
-        40 {
-          label = Blockbuster Card
-          name = creditcard
-        }
-      }
-
-      20 = TEXTLINE
-      20 {
-        label = Card number
-      }
-
-      30 = TEXTLINE
-      30 {
-        label = Expiry date
-      }
-    }
-
-    40 = SUBMIT
-    40 {
-      value = Submit my details
-    }
-  }
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Header/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Header/Index.rst
deleted file mode 100644
index 3b8940f963e8228fdafb0b1f946298020df2f9e4..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Header/Index.rst
+++ /dev/null
@@ -1,30 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-header:
-
-======
-HEADER
-======
-
-Creates a textual headline wrapped with a headline tag (e.g. h1). This
-element can be used for a visual separation or transportation of content. It
-is neither displayed on the confirmation page nor in the email.
-
-.. _reference-header-content:
-
-content
-=======
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-content`.
-
-
-.. _reference-header-headingSize:
-
-headingSize
-===========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-headingSize`.
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Hidden/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Hidden/Index.rst
deleted file mode 100644
index 727c6d6fb6dc49c174c2166ba77f3cd0b00a6484..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Hidden/Index.rst
+++ /dev/null
@@ -1,100 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-hidden:
-
-======
-HIDDEN
-======
-
-Creates a hidden control.
-
-Authors may create controls that are not rendered (visually) but whose
-values are submitted with a form. This control type can generally be used to
-store information between client/ server exchanges that would otherwise
-be lost due to the stateless nature of HTTP (see [RFC2616]).
-
-
-.. _reference-hidden-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-hidden-filters:
-
-filters
-=======
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-filters`.
-
-
-.. _reference-hidden-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-id`.
-
-
-.. _reference-hidden-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-lang`.
-
-
-.. _reference-hidden-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-hidden`
-    specific information.
-
-
-.. _reference-hidden-name:
-
-name
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-name`.
-
-
-.. _reference-hidden-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-style`.
-
-
-.. _reference-hidden-type:
-
-type
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-type`.
-
-
-.. _reference-hidden-value:
-
-value
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-value`.
-
-[tsref:(cObject).FORM.FormObject.HIDDEN]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Index.rst
deleted file mode 100644
index 1ef14fbab5ef4562c5cf529d0c3decf8eb671073..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Index.rst
+++ /dev/null
@@ -1,172 +0,0 @@
-.. include:: ../../Includes.txt
-
-
-.. _form-objects:
-
-============
-FORM objects
-============
-
-The editor is not bound to FORM objects shown below. Whenever FORM will be
-put in TypoScript, the contents of this property will be sent to the
-FORM plugin. However, one can use regular TYPO3 content objects (cObjects)
-as well. This means the integrator has the possibility to add COA, TEXT or
-even HMENU in the FORM TypoScript.
-
-Due to technical limitations it is **not** possible to nest form objects
-inside content objects. The following nesting will not work:
-:ts:`FORM` > :ts:`COA` > :ts:`TEXTLINE`.
-
-Furthermore, using cObjects is only allowed when **not** using the form
-content element/ wizard in the backend. This is due to security reasons.
-The functionality is only available when embedding a form directly in the
-TypoScript setup.
-
-.. toctree::
-    :maxdepth: 5
-    :titlesonly:
-    :glob:
-
-    ObjectAttributes/Index
-    Button/Index
-    Checkbox/Index
-    Fieldset/Index
-    Fileupload/Index
-    Form/Index
-    Header/Index
-    Hidden/Index
-    Optgroup/Index
-    Option/Index
-    Password/Index
-    Radio/Index
-    Reset/Index
-    Select/Index
-    Submit/Index
-    Textarea/Index
-    Textblock/Index
-    Textline/Index
-
-============== ================================================= ================================================= ================================================= ================================================= ====================================================== ===================================================
-Element        BUTTON                                            CHECKBOX                                          FIELDSET                                          FILEUPLOAD                                        FORM                                                   HEADER
-============== ================================================= ================================================= ================================================= ================================================= ====================================================== ===================================================
-accept                                                                                                                                                                                                                 :ref:`X <reference-objects-attributes-accept>`
-accept-charset                                                                                                                                                                                                         :ref:`X <reference-objects-attributes-accept-charset>`
-accesskey      :ref:`X <reference-objects-attributes-accesskey>` :ref:`X <reference-objects-attributes-accesskey>`                                                   :ref:`X <reference-objects-attributes-accesskey>`
-action                                                                                                                                                                                                                 :ref:`X <reference-objects-attributes-action>`
-alt            :ref:`X <reference-objects-attributes-alt>`       :ref:`X <reference-objects-attributes-alt>`                                                         :ref:`X <reference-objects-attributes-alt>`
-checked                                                          :ref:`X <reference-objects-attributes-checked>`
-class          :ref:`X <reference-objects-attributes-class>`     :ref:`X <reference-objects-attributes-class>`     :ref:`X <reference-objects-attributes-class>`     :ref:`X <reference-objects-attributes-class>`     :ref:`X <reference-objects-attributes-class>`
-content                                                                                                                                                                                                                                                                       :ref:`X <reference-objects-attributes-content>`
-cols
-data
-dir            :ref:`X <reference-objects-attributes-dir>`       :ref:`X <reference-objects-attributes-dir>`       :ref:`X <reference-objects-attributes-dir>`       :ref:`X <reference-objects-attributes-dir>`       :ref:`X <reference-objects-attributes-dir>`
-disabled       :ref:`X <reference-objects-attributes-disabled>`  :ref:`X <reference-objects-attributes-disabled>`                                                    :ref:`X <reference-objects-attributes-disabled>`
-enctyp                                                                                                                                                                                                                 :ref:`X <reference-objects-attributes-enctype>`
-filters
-headingSize                                                                                                                                                                                                                                                                   :ref:`X <reference-objects-attributes-headingSize>`
-id             :ref:`X <reference-objects-attributes-id>`        :ref:`X <reference-objects-attributes-id>`        :ref:`X <reference-objects-attributes-id>`        :ref:`X <reference-objects-attributes-id>`        :ref:`X <reference-objects-attributes-id>`
-label          :ref:`X <reference-objects-attributes-label>`     :ref:`X <reference-objects-attributes-label>`                                                       :ref:`X <reference-objects-attributes-label>`
-lang           :ref:`X <reference-objects-attributes-lang>`      :ref:`X <reference-objects-attributes-lang>`      :ref:`X <reference-objects-attributes-lang>`      :ref:`X <reference-objects-attributes-lang>`      :ref:`X <reference-objects-attributes-lang>`
-layout         :ref:`X <reference-layout>`                       :ref:`X <reference-layout>`                       :ref:`X <reference-layout>`                       :ref:`X <reference-layout>`                       :ref:`X <reference-layout>`
-legend                                                                                                             :ref:`X <reference-objects-attributes-legend>`
-maxlength
-method                                                                                                                                                                                                                 :ref:`X <reference-objects-attributes-method>`
-multiple
-name           :ref:`X <reference-objects-attributes-name>`      :ref:`X <reference-objects-attributes-name>`                                                        :ref:`X <reference-objects-attributes-name>`      :ref:`X <reference-objects-attributes-name>`
-postProcessor                                                                                                                                                                                                          :ref:`X <reference-objects-attributes-postProcessor>`
-prefix                                                                                                                                                                                                                 :ref:`X <reference-objects-attributes-prefix>`
-readonly
-rows
-rules                                                                                                                                                                                                                  :ref:`X <reference-objects-attributes-rules>`
-selected
-size                                                                                                                                                                 :ref:`X <reference-objects-attributes-size>`
-src
-style          :ref:`X <reference-objects-attributes-style>`     :ref:`X <reference-objects-attributes-style>`     :ref:`X <reference-objects-attributes-style>`     :ref:`X <reference-objects-attributes-style>`     :ref:`X <reference-objects-attributes-style>`
-tabindex       :ref:`X <reference-objects-attributes-tabindex>`  :ref:`X <reference-objects-attributes-tabindex>`                                                    :ref:`X <reference-objects-attributes-tabindex>`
-title          :ref:`X <reference-objects-attributes-title>`     :ref:`X <reference-objects-attributes-title>`                                                       :ref:`X <reference-objects-attributes-title>`     :ref:`X <reference-objects-attributes-title>`
-type           :ref:`X <reference-objects-attributes-type>`      :ref:`X <reference-objects-attributes-type>`                                                        :ref:`X <reference-objects-attributes-type>`
-value          :ref:`X <reference-objects-attributes-value>`     :ref:`X <reference-objects-attributes-value>`
-============== ================================================= ================================================= ================================================= ================================================= ====================================================== ===================================================
-
-============== ================================================= ================================================= ================================================= ================================================= ================================================= =================================================
-Element        HIDDEN                                            OPTGROUP                                          OPTION                                            PASSWORD                                          RADIO                                             RESET
-============== ================================================= ================================================= ================================================= ================================================= ================================================= =================================================
-accept
-accept-charset
-accesskey                                                                                                                                                            :ref:`X <reference-objects-attributes-accesskey>` :ref:`X <reference-objects-attributes-accesskey>` :ref:`X <reference-objects-attributes-accesskey>`
-action
-alt                                                                                                                                                                  :ref:`X <reference-objects-attributes-alt>`       :ref:`X <reference-objects-attributes-alt>`       :ref:`X <reference-objects-attributes-alt>`
-checked                                                                                                                                                                                                                :ref:`X <reference-objects-attributes-checked>`
-class          :ref:`X <reference-objects-attributes-class>`     :ref:`X <reference-objects-attributes-class>`     :ref:`X <reference-objects-attributes-class>`     :ref:`X <reference-objects-attributes-class>`     :ref:`X <reference-objects-attributes-class>`     :ref:`X <reference-objects-attributes-class>`
-content
-cols
-data                                                                                                               :ref:`X <reference-objects-attributes-data>`
-dir                                                                                                                                                                  :ref:`X <reference-objects-attributes-dir>`       :ref:`X <reference-objects-attributes-dir>`       :ref:`X <reference-objects-attributes-dir>`
-disabled                                                         :ref:`X <reference-objects-attributes-disabled>`  :ref:`X <reference-objects-attributes-disabled>`  :ref:`X <reference-objects-attributes-disabled>`  :ref:`X <reference-objects-attributes-disabled>`  :ref:`X <reference-objects-attributes-disabled>`
-enctype
-filters        :ref:`X <reference-objects-attributes-filters>`                                                                                                       :ref:`X <reference-objects-attributes-filters>`
-headingSize
-id             :ref:`X <reference-objects-attributes-id>`        :ref:`X <reference-objects-attributes-id>`        :ref:`X <reference-objects-attributes-id>`        :ref:`X <reference-objects-attributes-id>`        :ref:`X <reference-objects-attributes-id>`        :ref:`X <reference-objects-attributes-id>`
-label                                                            :ref:`X <reference-objects-attributes-label>`     :ref:`X <reference-objects-attributes-label>`     :ref:`X <reference-objects-attributes-label>`     :ref:`X <reference-objects-attributes-label>`     :ref:`X <reference-objects-attributes-label>`
-lang           :ref:`X <reference-objects-attributes-lang>`      :ref:`X <reference-objects-attributes-lang>`      :ref:`X <reference-objects-attributes-lang>`      :ref:`X <reference-objects-attributes-lang>`      :ref:`X <reference-objects-attributes-lang>`      :ref:`X <reference-objects-attributes-lang>`
-layout         :ref:`X <reference-layout>`                       :ref:`X <reference-layout>`                       :ref:`X <reference-layout>`                       :ref:`X <reference-layout>`                       :ref:`X <reference-layout>`                       :ref:`X <reference-layout>`
-legend
-maxlength                                                                                                                                                            :ref:`X <reference-objects-attributes-maxlength>`
-method
-multiple
-name           :ref:`X <reference-objects-attributes-name>`                                                                                                          :ref:`X <reference-objects-attributes-name>`      :ref:`X <reference-objects-attributes-name>`      :ref:`X <reference-objects-attributes-name>`
-postProcessor
-prefix
-readonly                                                                                                                                                             :ref:`X <reference-objects-attributes-readonly>`
-rows
-rules
-selected                                                                                                           :ref:`X <reference-objects-attributes-selected>`
-size                                                                                                                                                                 :ref:`X <reference-objects-attributes-size>`
-style          :ref:`X <reference-objects-attributes-style>`     :ref:`X <reference-objects-attributes-style>`     :ref:`X <reference-objects-attributes-style>`     :ref:`X <reference-objects-attributes-style>`     :ref:`X <reference-objects-attributes-style>`     :ref:`X <reference-objects-attributes-style>`
-tabindex                                                                                                                                                             :ref:`X <reference-objects-attributes-tabindex>`  :ref:`X <reference-objects-attributes-tabindex>`  :ref:`X <reference-objects-attributes-tabindex>`
-title                                                            :ref:`X <reference-objects-attributes-title>`     :ref:`X <reference-objects-attributes-title>`     :ref:`X <reference-objects-attributes-title>`     :ref:`X <reference-objects-attributes-title>`     :ref:`X <reference-objects-attributes-title>`
-type           :ref:`X <reference-objects-attributes-type>`                                                                                                          :ref:`X <reference-objects-attributes-type>`      :ref:`X <reference-objects-attributes-type>`      :ref:`X <reference-objects-attributes-type>`
-value          :ref:`X <reference-objects-attributes-value>`                                                       :ref:`X <reference-objects-attributes-value>`     :ref:`X <reference-objects-attributes-value>`     :ref:`X <reference-objects-attributes-value>`     :ref:`X <reference-objects-attributes-value>`
-============== ================================================= ================================================= ================================================= ================================================= ================================================= =================================================
-
-============== ================================================= ================================================= ================================================= ================================================= =================================================
-Element        SELECT                                            SUBMIT                                            TEXTAREA                                          TEXTBLOCK                                         TEXTLINE
-============== ================================================= ================================================= ================================================= ================================================= =================================================
-accept
-accept-charset
-accesskey                                                        :ref:`X <reference-objects-attributes-accesskey>` :ref:`X <reference-objects-attributes-accesskey>`                                                   :ref:`X <reference-objects-attributes-accesskey>`
-action
-alt                                                              :ref:`X <reference-objects-attributes-alt>`                                                                                                           :ref:`X <reference-objects-attributes-alt>`
-checked
-class          :ref:`X <reference-objects-attributes-class>`     :ref:`X <reference-objects-attributes-class>`     :ref:`X <reference-objects-attributes-class>`                                                       :ref:`X <reference-objects-attributes-class>`
-content                                                                                                                                                              :ref:`X <reference-objects-attributes-content>`
-cols                                                                                                               :ref:`X <reference-objects-attributes-cols>`
-data
-dir                                                              :ref:`X <reference-objects-attributes-dir>`       :ref:`X <reference-objects-attributes-dir>`                                                         :ref:`X <reference-objects-attributes-dir>`
-disabled       :ref:`X <reference-objects-attributes-disabled>`  :ref:`X <reference-objects-attributes-disabled>`  :ref:`X <reference-objects-attributes-disabled>`                                                    :ref:`X <reference-objects-attributes-disabled>`
-enctype
-filters
-headingSize
-id             :ref:`X <reference-objects-attributes-id>`        :ref:`X <reference-objects-attributes-id>`        :ref:`X <reference-objects-attributes-id>`                                                          :ref:`X <reference-objects-attributes-id>`
-label          :ref:`X <reference-objects-attributes-label>`     :ref:`X <reference-objects-attributes-label>`     :ref:`X <reference-objects-attributes-label>`                                                       :ref:`X <reference-objects-attributes-label>`
-lang           :ref:`X <reference-objects-attributes-lang>`      :ref:`X <reference-objects-attributes-lang>`      :ref:`X <reference-objects-attributes-lang>`                                                        :ref:`X <reference-objects-attributes-lang>`
-layout         :ref:`X <reference-layout>`                       :ref:`X <reference-layout>`
-legend
-maxlength                                                                                                                                                                                                              :ref:`X <reference-objects-attributes-maxlength>`
-method
-multiple       :ref:`X <reference-objects-attributes-multiple>`
-name           :ref:`X <reference-objects-attributes-name>`      :ref:`X <reference-objects-attributes-name>`      :ref:`X <reference-objects-attributes-name>`                                                        :ref:`X <reference-objects-attributes-name>`
-postProcessor
-prefix
-readonly                                                                                                           :ref:`X <reference-objects-attributes-readonly>`                                                    :ref:`X <reference-objects-attributes-readonly>`
-rows                                                                                                               :ref:`X <reference-objects-attributes-rows>`
-rules
-selected
-size           :ref:`X <reference-objects-attributes-size>`                                                                                                                                                            :ref:`X <reference-objects-attributes-size>`
-style          :ref:`X <reference-objects-attributes-style>`     :ref:`X <reference-objects-attributes-style>`     :ref:`X <reference-objects-attributes-style>`                                                       :ref:`X <reference-objects-attributes-style>`
-tabindex       :ref:`X <reference-objects-attributes-tabindex>`  :ref:`X <reference-objects-attributes-tabindex>`  :ref:`X <reference-objects-attributes-tabindex>`                                                    :ref:`X <reference-objects-attributes-tabindex>`
-title          :ref:`X <reference-objects-attributes-title>`     :ref:`X <reference-objects-attributes-title>`     :ref:`X <reference-objects-attributes-title>`                                                       :ref:`X <reference-objects-attributes-title>`
-type                                                             :ref:`X <reference-objects-attributes-type>`
-value                                                            :ref:`X <reference-objects-attributes-value>`                                                                                                         :ref:`X <reference-objects-attributes-value>`
-============== ================================================= ================================================= ================================================= ================================================= =================================================
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/ObjectAttributes/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/ObjectAttributes/Index.rst
deleted file mode 100644
index a95d2f1d9d52d7851a292db4c753013bc4f69fbb..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/ObjectAttributes/Index.rst
+++ /dev/null
@@ -1,973 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-object-attributes:
-
-=================
-Object Attributes
-=================
-
-.. contents::
-    :local:
-    :depth: 1
-
-
-.. _reference-objects-attributes-accept:
-
-accept
-======
-
-:aspect:`Property:`
-    accept
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    This attribute specifies a comma-separated list of content types that a
-    server processing this form will handle correctly.
-
-    User agents may use this information to filter out non-conforming files
-    when prompting a user to select files to be sent to the server (cf. the
-    INPUT element when type="file").
-
-    RFC2045: For a complete list, see http://www.iana.org/assignments/media-types/
-
-
-.. _reference-objects-attributes-accept-charset:
-
-accept-charset
-==============
-
-:aspect:`Property:`
-    accept-charset
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    This attribute specifies the list of character encodings for input data
-    that is accepted by the server processing this form.
-
-    The value is a space- and/or comma-delimited list of charset values.
-
-    The client must interpret this list as an exclusive-or list. I.e., the
-    server is able to accept any single character encoding per entity
-    received.
-
-    The default value for this attribute is the reserved string "UNKNOWN".
-    User agents may interpret this value as the character encoding that was
-    used to transmit the document containing this FORM element.
-
-    RFC2045: For a complete list, see http://www.iana.org/assignments/character-sets/
-
-
-.. _reference-objects-attributes-accesskey:
-
-accesskey
-=========
-
-:aspect:`Property:`
-    accesskey
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    This attribute assigns an access key to an element.
-
-    An access key is a single character from the document character set.
-
-    **Note**: Authors should consider the input method of the expected
-    reader when specifying an accesskey.
-
-    Pressing an access key assigned to an element gives focus to the
-    element.
-
-    The action that occurs when an element receives focus depends on the
-    element. For example, when a user activates a link defined by the
-    element, the user agent generally follows the link. When a user
-    activates a radio button, the user agent changes the value of the radio
-    button. When the user activates a text field, it allows input, etc.
-
-
-.. _reference-objects-attributes-action:
-
-action
-======
-
-:aspect:`Property:`
-    action
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    This attribute specifies a form processing agent.
-
-    In normal circumstances the action attribute will be filled
-    automatically, because the form must call the same URI where the form
-    resides.
-
-    Besides specifying a page uid it is also possible to set an anchor. See
-    the examples below.
-
-    .. code-block:: typoscript
-
-      action = #anchor
-      action = 4#anchor
-
-
-.. _reference-objects-attributes-alt:
-
-alt
-===
-
-:aspect:`Property:`
-    alt
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    For user agents that cannot display images, forms, or applets, this
-    attribute specifies alternative text. The language of this text is
-    specified by the lang attribute.
-
-
-.. _reference-objects-attributes-checked:
-
-checked
-=======
-
-:aspect:`Property:`
-    checked
-
-:aspect:`Data type:`
-    boolean/ checked
-
-:aspect:`Description:`
-    When the type attribute has the value "radio" or "checkbox", this
-    boolean attribute specifies that the button is activated.
-
-    User agents must ignore this attribute for other control types.
-
-    **Examples:**
-
-    .. code-block:: typoscript
-
-      checked = 1
-      checked = 0
-      checked = checked
-
-
-.. _reference-objects-attributes-class:
-
-class
-=====
-
-:aspect:`Property:`
-    class
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    This attribute assigns a class name or set of class names to an element.
-
-    Any number of elements may be assigned the same class name or names.
-
-    Multiple class names must be separated by white space characters.
-
-
-.. _reference-objects-attributes-cols:
-
-cols
-====
-
-:aspect:`Property:`
-    cols
-
-:aspect:`Data type:`
-    integer
-
-:aspect:`Description:`
-    This attribute specifies the visible width.
-
-    Users should be able to enter longer lines than this, so user agents
-    should provide some means to scroll through the contents of the control
-    when the contents extend beyond the visible area. User agents may wrap
-    visible text lines to keep long lines visible without the need for
-    scrolling.
-
-:aspect:`Default:`
-    40
-
-
-.. _reference-objects-attributes-content:
-
-content
-=======
-
-:aspect:`Property:`
-    content
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    This attribute contains the content of a FORM object.
-
-
-.. _reference-objects-attributes-data:
-
-data
-====
-
-:aspect:`Property:`
-    data
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    This attribute contains the content of a FORM object.
-
-
-.. _reference-objects-attributes-dir:
-
-dir
-===
-
-:aspect:`Property:`
-    dir
-
-:aspect:`Data type:`
-    ltr/ rtl
-
-:aspect:`Description:`
-    This attribute specifies the base direction of directionally neutral
-    text (i.e., text that does not have inherent directionality as defined
-    in [UNICODE]) in an element's content and attribute values.
-
-    It also specifies the directionality of tables. Possible values:
-
-    - LTR: Left-to-right text or table.
-
-    - RTL: Right-to-left text or table.
-
-    In addition to specifying the language of a document with the lang
-    attribute, authors may need to specify the base directionality
-    (left-to-right or right-to-left) of portions of a document's text, of a
-    table structure, etc. This is done with the dir attribute.
-
-
-.. _reference-objects-attributes-disabled:
-
-disabled
-========
-
-:aspect:`Property:`
-    disabled
-
-:aspect:`Data type:`
-    boolean/ disabled
-
-:aspect:`Description:`
-    When set for a form control, this boolean attribute disables the control
-    for user input.
-
-    When set, the disabled attribute has the following effects on an
-    element:
-
-    - Disabled controls do not receive focus.
-
-    - Disabled controls are skipped in tabbing navigation.
-
-    - Disabled controls cannot be successful.
-
-    This attribute is inherited but local declarations override the
-    inherited value.
-
-    How disabled elements are rendered depends on the user agent. For
-    example, some user agents "gray out" disabled menu items, button labels,
-    etc.
-
-    **Examples:**
-
-    .. code-block:: typoscript
-
-      disabled = 1
-      disabled = 0
-      disabled = disabled
-
-
-.. _reference-objects-attributes-enctype:
-
-enctype
-=======
-
-:aspect:`Property:`
-    enctype
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    This attribute specifies the content type used to submit the form to the
-    server (when the value of method is "post"). The default value for this
-    attribute is "application/x-www-form-urlencoded".
-
-    The value "multipart/form-data" should be used in combination with the
-    INPUT element, type="file".
-
-:aspect:`Default:`
-    application/x-www-form-urlencoded
-
-
-.. _reference-objects-attributes-filters:
-
-filters
-=======
-
-:aspect:`Property:`
-    filters
-
-:aspect:`Data type:`
-    [array of numbers]
-
-    ->filters
-
-:aspect:`Description:`
-    Add filters to the FORM object.
-
-    This accepts multiple filters for one FORM object, but you have to add
-    these filters one by one. The submitted data for this particular object
-    will be filtered by the assigned filters in the given order.
-
-    The filtered data will be shown to the visitor when there are errors in
-    the form or on a confirmation page. Otherwise the filtered data will be
-    send by mail to the receiver.
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      filters {
-        1 = alphabetic
-        1 (
-          allowWhiteSpace = 1
-        )
-        2 = titlecase
-      }
-
-    **Submitted data:** john doe3
-
-    **Filtered:** John Doe
-
-:aspect:`Default:`
-    .. code-block:: typoscript
-
-      filters {
-        0 = trim
-      }
-
-
-.. _reference-objects-attributes-headingSize:
-
-headingSize
-===========
-
-:aspect:`Property:`
-    headingSize
-
-:aspect:`Data type:`
-    h1, h2, h3, h4, h5
-
-:aspect:`Description:`
-    This attributes allows to wrap the content of a FORM object with a
-    headline tag.
-
-:aspect:`Default:`
-    h1
-
-
-.. _reference-objects-attributes-id:
-
-id
-==
-
-:aspect:`Property:`
-    id
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    This attribute assigns an id to an element.
-
-    This id must be unique in a document.
-
-    If an id has been assigned to the object and a value has been entered
-    for the label, the "for" attribute will inherit the id.
-
-    **Example for FORM object BUTTON:**
-
-    .. code-block:: html
-
-      <label for="click">Push this button</label>
-      <input type="button" id="click" value="Click me" />
-
-
-.. _reference-objects-attributes-label:
-
-label
-=====
-
-:aspect:`Property:`
-    label
-
-:aspect:`Data type:`
-    string/ cObject
-
-:aspect:`Description:`
-    The value of the label of a FORM object.
-
-    By default the value of the label is a TEXT cObject, but you can use
-    other cObjects as well. When no cObject type is used it assumes you want
-    to use TEXT. In this case you can assign the value directly to the label
-    property or indirectly to the value property of the label.
-
-    For more information about cObjects, take a look in the document TSREF.
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      label = TEXT
-      label {
-        value = First name
-      }
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      label = First name
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      label.value = First name
-
-
-.. _reference-objects-attributes-lang:
-
-lang
-====
-
-:aspect:`Property:`
-    lang
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    This attribute specifies the base language of an element's attribute
-    values and text content. The default value of this attribute is unknown.
-
-    Briefly, language codes consist of a primary code and a possibly empty
-    series of subcodes:
-
-    - language-code = primary-code ( "-" subcode )\*
-
-    Here are some sample language codes:
-
-    - *en*: English
-
-    - *en-US*: the U.S. version of English
-
-    - *en-cockney*: the Cockney version of English
-
-    - *i-navajo*: the Navajo language spoken by some Native Americans
-
-    - *x-klingon*: The primary tag "x" indicates an experimental language tag
-
-
-.. _reference-objects-attributes-layout:
-
-layout
-======
-
-:aspect:`Property:`
-    layout
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-layout`.
-
-
-.. _reference-objects-attributes-legend:
-
-legend
-======
-
-:aspect:`Property:`
-    legend
-
-:aspect:`Data type:`
-    string/ cObject
-
-:aspect:`Description:`
-    The value of the legend of a FORM object.
-
-    By default the value of the legend is a TEXT cObject, but you can use
-    other cObjects as well. When no cObject type is used it assumes you want
-    to use TEXT. In this case you can assign the value directly to the
-    legend property or indirectly to the value property of the legend.
-
-    For more information about cObjects, take a look in the document TSREF.
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      legend = TEXT
-      legend {
-        value = Personal information
-      }
-
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      legend = Personal information
-
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      legend.value = Personal information
-
-
-.. _reference-objects-attributes-maxlength:
-
-maxlength
-=========
-
-:aspect:`Property:`
-    maxlength
-
-:aspect:`Data type:`
-    integer
-
-:aspect:`Description:`
-    This attribute specifies the maximum number of characters the user may
-    enter. This number may exceed the specified size, in which case the user
-    agent should offer a scrolling mechanism. The default value for this
-    attribute is an unlimited number.
-
-
-.. _reference-objects-attributes-method:
-
-method
-======
-
-:aspect:`Property:`
-    method
-
-:aspect:`Data type:`
-    post/ get
-
-:aspect:`Description:`
-    Specifies which HTTP method will be used to submit form data.
-
-    Only form data submitted with the entered or default method will be
-    processed.
-
-:aspect:`Default:`
-    get
-
-
-.. _reference-objects-attributes-multiple:
-
-multiple
-========
-
-:aspect:`Property:`
-    multiple
-
-:aspect:`Data type:`
-    boolean/ multiple
-
-:aspect:`Description:`
-    If set, this boolean attribute allows multiple selections.
-
-    If not set, the SELECT element only permits single selections.
-
-    **Examples:**
-
-    .. code-block:: typoscript
-
-      multiple = 1
-      multiple = 0
-      multiple = multiple
-
-
-.. _reference-objects-attributes-name:
-
-name
-====
-
-:aspect:`Property:`
-    name
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    This attribute names the element so that submitted data can be
-    identified by processing the form server side.
-
-    If no name has been given, it will get assigned an internal counter
-    together with the prefix, like:
-
-    .. code-block:: html
-
-      <input type="button" name="tx_form[21]" value="click" />
-      <input type="checkbox" name="tx_form[22]" value="click" />
-
-
-.. _reference-objects-attributes-postProcessor:
-
-postProcessor
-=============
-
-:aspect:`Property:`
-    postProcessor
-
-:aspect:`Data type:`
-    [array of numbers]
-
-:aspect:`Description:`
-    Add postprocessors to the FORM.
-
-    This accepts multiple postprocessors for one FORM object, but they have
-    to be added one by one.
-
-    **Example** :
-
-    .. code-block:: typoscript
-
-      postProcessor {
-        1 = mail
-        1 {
-          recipientEmail = bar@foo.org
-          senderEmail = foo@bar.com
-        }
-      }
-
-
-.. _reference-objects-attributes-prefix:
-
-prefix
-======
-
-:aspect:`Property:`
-    prefix
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    The prefix of the values in the name attributes of the FORM objects.
-
-    <input name=" **prefix** [first\_name]" value="" />
-
-:aspect:`Default:`
-    tx\_form
-
-
-.. _reference-objects-attributes-readonly:
-
-readonly
-========
-
-:aspect:`Property:`
-    readonly
-
-:aspect:`Data type:`
-    boolean/ readonly
-
-:aspect:`Description:`
-    When set for a form control, this boolean attribute prohibits changes to
-    the control.
-
-    The readonly attribute specifies whether the control may be modified by
-    the user.
-
-    When set, the readonly attribute has the following effects on an
-    element:
-
-    - Read-only elements receive focus but cannot be modified by the user.
-
-    - Read-only elements are included in tabbing navigation.
-
-    - Read-only elements may be successful.
-
-    How read-only elements are rendered depends on the user agent.
-
-    **Examples:**
-
-    .. code-block:: html
-
-      readonly = 1
-      readonly = 0
-      readonly = disabled
-
-    **Note**: The only way to modify dynamically the value of the readonly
-    attribute is through a script.
-
-
-.. _reference-objects-attributes-rows:
-
-rows
-====
-
-:aspect:`Property:`
-    rows
-
-:aspect:`Data type:`
-    integer
-
-:aspect:`Description:`
-    This attribute specifies the number of visible text lines.
-
-    Users should be able to enter more lines than this, so user agents
-    should provide some means to scroll through the contents of the control
-    when the contents extend beyond the visible area.
-
-:aspect:`Default:`
-    5
-
-
-.. _reference-objects-attributes-rules:
-
-rules
-=====
-
-:aspect:`Property:`
-    rules
-
-:aspect:`Data type:`
-    [array of numbers]
-
-:aspect:`Description:`
-    Add validation rules to the FORM.
-
-    This accepts multiple validation rules for one FORM object, but the
-    rules have to be added one by one. It is also possible to add validation
-    rules for different FORM objects.
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      rules {
-        1 = required
-        1 {
-          element = first_name
-        }
-        2 = required
-        2 {
-          element = last_name
-          showMessage = 0
-          error = TEXT
-          error {
-            value = Please enter your last name
-          }
-        }
-      }
-
-    Validation rules are a powerful tool to add validation to the form.
-    Please take a look at the rules section in this manual.
-
-
-.. _reference-objects-attributes-selected:
-
-selected
-========
-
-:aspect:`Property:`
-    selected
-
-:aspect:`Data type:`
-    boolean/ selected
-
-:aspect:`Description:`
-    When set, this boolean attribute specifies that a option is pre-
-    selected.
-
-    **Examples:**
-
-    .. code-block:: typoscript
-
-      selected = 1
-      selected = 0
-      selected = selected
-
-
-.. _reference-objects-attributes-size:
-
-size
-====
-
-:aspect:`Property:`
-    size
-
-:aspect:`Data type:`
-    integer
-
-:aspect:`Description:`
-    This attribute tells the user agent the initial width of the control.
-    The size has to be entered as integer without any measuring unit.
-
-
-.. _reference-objects-attributes-src:
-
-src
-===
-
-:aspect:`Property:`
-    src
-
-:aspect:`Data type:`
-    imgResource
-
-:aspect:`Description:`
-    This attribute specifies the location of the image to be used to
-    decorate the graphical submit button. GIFBUILDER objects are not
-    allowed.
-
-
-.. _reference-objects-attributes-style:
-
-style
-=====
-
-:aspect:`Property:`
-    style
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    This attribute specifies CSS style information for the current element.
-
-
-.. _reference-objects-attributes-tabindex:
-
-tabindex
-========
-
-:aspect:`Property:`
-    tabindex
-
-:aspect:`Data type:`
-    integer
-
-:aspect:`Description:`
-    This attribute specifies the position of the current element in the
-    tabbing order for the current document. This value must be a number
-    between 0 and 32767. User agents should ignore leading zeros.
-
-    The tabbing order defines the order in which elements will receive focus
-    when navigated by the user via the keyboard. The tabbing order may
-    include elements nested within other elements.
-
-    Elements that may receive focus should be navigated by user agents
-    according to the following rules:
-
-    #. Those elements that support the tabindex attribute and assign a
-       positive value to it are navigated first. Navigation proceeds from
-       the element with the lowest tabindex value to the element with the
-       highest value. Values neither need to be sequential nor must begin
-       with any particular value. Elements that have identical tabindex
-       values should be navigated in the order they appear in the character
-       stream.
-
-    #. Those elements that do not support the tabindex attribute or support
-       it and assign it a value of "0" are navigated next. These elements
-       are navigated in the order they appear in the character stream.
-
-    #. Elements that are disabled do not participate in the tabbing order.
-
-    The actual key sequence that causes tabbing navigation or element
-    activation depends on the configuration of the user agent (e.g., the
-    "tab" key is used for navigation and the "enter" key is used to activate
-    a selected element),
-
-    User agents may also define key sequences to navigate the tabbing order
-    in reverse. When the end (or beginning) of the tabbing order is reached,
-    user agents may circle back to the beginning (or end).
-
-
-.. _reference-objects-attributes-title:
-
-title
-=====
-
-:aspect:`Property:`
-    title
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    This attribute offers advisory information about the element for which
-    it is set. Unlike the TITLE element, which provides information about an
-    entire document and may only appear once, the title attribute may
-    annotate any number of elements. Please consult an element's definition
-    to verify that it supports this attribute.
-
-    Values of the title attribute may be rendered by user agents in a
-    variety of ways. For instance, visual browsers frequently display the
-    title as a "tool tip" (a short message that appears when the pointing
-    device pauses over an object). Audio user agents may speak the title
-    information in a similar context.
-
-
-.. _reference-objects-attributes-type:
-
-type
-====
-
-:aspect:`Property:`
-    type
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Defines the type of form input control to create.
-
-
-.. _reference-objects-attributes-value:
-
-value
-=====
-
-:aspect:`Property:`
-    value
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    This attribute assigns the initial value to the object.
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Optgroup/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Optgroup/Index.rst
deleted file mode 100644
index 5a9e74266d96857239656fb5b5843810da21b098..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Optgroup/Index.rst
+++ /dev/null
@@ -1,110 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-optgroup:
-
-========
-OPTGROUP
-========
-
-The OPTGROUP element allows authors to group choices logically. This is
-particularly helpful when the user must choose from a long list of options;
-groups of related choices are easier to grasp and remember than a single
-long list of options. All OPTGROUP elements must be specified directly
-within a SELECT element (i.e., groups may not be nested).
-
-An OPTGROUP object can only exist between a SELECT object.
-
-
-.. _reference-optgroup-1-2-3-4:
-
-1, 2, 3, 4 ...
-==============
-
-:aspect:`Property:`
-    1, 2, 3, 4 ...
-
-:aspect:`Data type:`
-    [array of FORM objects]
-
-:aspect:`Description:`
-    OPTION objects, part of the OPTGROUP
-
-
-.. _reference-optgroup-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-optgroup-disabled:
-
-disabled
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-disabled`.
-
-
-.. _reference-optgroup-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-id`.
-
-
-.. _reference-optgroup-label:
-
-label
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-label`.
-
-:aspect:`Default:`
-    optgroup
-
-
-.. _reference-optgroup-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-lang`.
-
-
-.. _reference-optgroup-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-optgroup`
-    specific information.
-
-
-.. _reference-optgroup-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-style`.
-
-
-.. _reference-optgroup-title:
-
-title
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-title`.
-
-[tsref:(cObject).FORM.FormObject.OPTGROUP]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Option/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Option/Index.rst
deleted file mode 100644
index 6db85eedc0f2d235bc03e129da85a29807ea4534..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Option/Index.rst
+++ /dev/null
@@ -1,115 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-option:
-
-======
-OPTION
-======
-
-Defines an element inside a select/ drop-down list.
-
-An OPTION object can only exist "between" a SELECT or OPTGROUP object.
-
-
-.. _reference-option-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-option-data:
-
-data
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-data`.
-
-
-.. _reference-option-disabled:
-
-disabled
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-disabled`.
-
-
-.. _reference-option-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-id`.
-
-
-.. _reference-option-label:
-
-label
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-label`.
-
-
-.. _reference-option-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-lang`.
-
-
-.. _reference-option-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-option`
-    specific information.
-
-
-.. _reference-option-selected:
-
-selected
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-selected`.
-
-
-.. _reference-option-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-style`.
-
-
-.. _reference-option-title:
-
-title
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-title`.
-
-
-.. _reference-option-value:
-
-value
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-value`.
-
-[tsref:(cObject).FORM.FormObject.OPTION]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Password/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Password/Index.rst
deleted file mode 100644
index be61de88fc218be9c989fce61ab28f1d9ea04159..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Password/Index.rst
+++ /dev/null
@@ -1,198 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-password:
-
-========
-PASSWORD
-========
-
-Creates a single-line text input control, but the input text is rendered in
-such a way as to hide the characters (e.g., a series of asterisks). This
-control type is often used for sensitive input such as passwords. Note that
-the current value is the text entered by the user, not the text rendered by
-the user agent.
-
-**Note** . Form designers should note that this mechanism affords only light
-security protection. Although the password is masked by user agents from
-casual observers, it is transmitted to the server in clear text, and may be
-read by anyone with low-level access to the network.
-
-
-.. _reference-password-accesskey:
-
-accesskey
-=========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-accesskey`.
-
-
-.. _reference-password-alt:
-
-alt
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-alt`.
-
-
-.. _reference-password-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-password-dir:
-
-dir
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-dir`.
-
-
-.. _reference-password-disabled:
-
-disabled
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-disabled`.
-
-
-.. _reference-password-filters:
-
-filters
-=======
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-filters`.
-
-
-.. _reference-password-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-id`.
-
-
-.. _reference-password-label:
-
-label
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-label`.
-
-
-.. _reference-password-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-lang`.
-    tag
-
-
-.. _reference-password-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-password`
-    specific information.
-
-
-.. _reference-password-maxlength:
-
-maxlength
-=========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-maxlength`.
-
-
-.. _reference-password-name:
-
-name
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-name`.
-
-
-.. _reference-password-readonly:
-
-readonly
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-readonly`.
-
-
-.. _reference-password-size:
-
-size
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-size`.
-
-
-.. _reference-password-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-style`.
-
-
-.. _reference-password-tabindex:
-
-tabindex
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-tabindex`.
-
-
-.. _reference-password-title:
-
-title
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-title`.
-
-
-.. _reference-password-type:
-
-type
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-type`.
-
-:aspect:`Default:`
-    password
-
-
-.. _reference-password-value:
-
-value
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-value`.
-
-[tsref:(cObject).FORM.FormObject.PASSWORD]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Radio/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Radio/Index.rst
deleted file mode 100644
index ce3df5edd327f03c120483602fe9c786f99f676d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Radio/Index.rst
+++ /dev/null
@@ -1,190 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-radio:
-
-=====
-RADIO
-=====
-
-Creates a radio button.
-
-Radio buttons are on/ off switches that may be toggled by the user. A switch
-is "on" when the control element's checked attribute is set. When a form is
-submitted, only "on" radio button controls can become successful.
-
-Several radio buttons in a form may share the same control name. Thus, for
-example, radio buttons allow users to select several values for the same
-property.
-
-Radio buttons are like checkboxes except that when several share the same
-control name, they are mutually exclusive: when one is switched "on", all
-others with the same name are switched "off".
-
-Radio buttons are normally grouped in a FIELDSET object.
-
-**Note from W3C for user agent behaviour**: If no radio button in a set
-sharing the same control name is initially "on", user agent behavior for
-choosing which control is initially "on" is undefined.
-
-**Note**: Since existing implementations handle this case differently, the
-current specification differs from RFC 1866 ([RFC1866] section 8.1.2.4),
-which states:
-
-At all times, exactly one of the radio buttons in a set is checked. If
-none of the elements of a set of radio buttons specifies \`checked',
-then the user agent must check the first radio button of the set initially.
-
-Since user agent behavior differs, authors should ensure that in each set of
-radio buttons that one is initially "on".
-
-
-.. _reference-radio-accesskey:
-
-accesskey
-=========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-accesskey`.
-
-
-.. _reference-radio-alt:
-
-alt
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-alt`.
-
-
-.. _reference-radio-checked:
-
-checked
-=======
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-checked`.
-
-
-.. _reference-radio-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-radio-dir:
-
-dir
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-dir`.
-
-
-.. _reference-radio-disabled:
-
-disabled
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-disabled`.
-
-
-.. _reference-radio-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-id`.
-
-
-.. _reference-radio-label:
-
-label
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-label`.
-
-
-.. _reference-radio-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-lang`.
-
-
-.. _reference-radio-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-radio`
-    specific information.
-
-
-.. _reference-radio-name:
-
-name
-====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-name`.
-
-
-.. _reference-radio-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-style`.
-
-
-.. _reference-radio-tabindex:
-
-tabindex
-========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-tabindex`.
-
-
-.. _reference-radio-title:
-
-title
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-title`.
-
-
-.. _reference-radio-type:
-
-type
-====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-type`.
-
-:aspect:`Default:`
-    radio
-
-
-.. _reference-radio-value:
-
-value
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-objects-attributes-value`.
-
-[tsref:(cObject).FORM.FormObject.RADIO]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Reset/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Reset/Index.rst
deleted file mode 100644
index 6854cdd9772da0788389f67244d59d2d0a26bc86..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Reset/Index.rst
+++ /dev/null
@@ -1,154 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-reset:
-
-=====
-RESET
-=====
-
-Creates a reset button.
-
-When activated, a reset button resets all controls to their initial values.
-
-
-.. _reference-reset-accesskey:
-
-accesskey
-=========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-accesskey`.
-
-
-.. _reference-reset-alt:
-
-alt
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-alt`.
-
-
-.. _reference-reset-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-reset-dir:
-
-dir
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-dir`.
-
-
-.. _reference-reset-disabled:
-
-disabled
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-disabled`.
-
-
-.. _reference-reset-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-id`.
-
-
-.. _reference-reset-label:
-
-label
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-label`.
-
-
-.. _reference-reset-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-lang`.
-
-
-.. _reference-reset-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-reset`
-    specific information.
-
-
-.. _reference-reset-name:
-
-name
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-name`.
-
-
-.. _reference-reset-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-style`.
-
-
-.. _reference-reset-tabindex:
-
-tabindex
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-tabindex`.
-
-
-.. _reference-reset-title:
-
-title
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-title`.
-
-
-.. _reference-reset-type:
-
-type
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-type`.
-
-:aspect:`Default:`
-    reset
-
-
-.. _reference-reset-value:
-
-value
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-value`.
-
-[tsref:(cObject).FORM.FormObject.RESET]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Select/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Select/Index.rst
deleted file mode 100644
index 314b2119397d8adf9d529d14eafe8acd60618e78..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Select/Index.rst
+++ /dev/null
@@ -1,165 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-select:
-
-======
-SELECT
-======
-
-The SELECT object creates a menu. Each choice offered by the menu is
-represented by an OPTION object. A SELECT object must contain at least one
-OPTION object
-
-**Pre-selected options**
-
-Zero or more choices may be pre-selected for the user. User agents should
-determine which choices are pre-selected as follows:
-
-- If no OPTION object has the selected attribute set, user agent behavior
-  for choosing which option is initially selected is undefined.
-  **Note**: Since existing implementations handle this case differently, the
-  current specification differs from RFC 1866 ([RFC1866] section 8.1.3),
-  which states: The initial state has the first option selected, unless a
-  SELECTED attribute is present on any of the <OPTION> elements. Since user
-  agent behavior differs, one should ensure that each menu includes a
-  default pre-selected OPTION.
-
-- If one OPTION object has the selected attribute set, it should be pre-
-  selected.
-
-- If the SELECT object has the multiple attribute set and more than one
-  OPTION object has the selected attribute set, they should all be pre-
-  selected.
-
-- It is considered an error if more than one OPTION object has the selected
-  attribute set and the SELECT object does not have the multiple attribute
-  set. User agents may vary in how they handle this error, but should not
-  pre-select more than one choice.
-
-
-.. _reference-select-1-2-3-4:
-
-1, 2, 3, 4 ...
-==============
-
-:aspect:`Property:`
-    1, 2, 3, 4 ...
-
-:aspect:`Data type:`
-    [array of FORM objects]
-
-:aspect:`Description:`
-    OPTION and/ or OPTGROUP objects, part of the SELECT.
-
-
-.. _reference-select-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-select-disabled:
-
-disabled
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-disabled`.
-
-
-.. _reference-select-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-id`.
-
-
-.. _reference-select-label:
-
-label
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-label`.
-
-
-.. _reference-select-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-lang`.
-
-
-.. _reference-select-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-select`
-    specific information.
-
-
-.. _reference-select-multiple:
-
-multiple
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-multiple`.
-
-
-.. _reference-select-name:
-
-name
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-name`.
-
-
-.. _reference-select-size:
-
-size
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-size`.
-
-
-.. _reference-select-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-style`.
-
-
-.. _reference-select-tabindex:
-
-tabindex
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-tabindex`.
-
-
-.. _reference-select-title:
-
-title
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-title`.
-
-[tsref:(cObject).FORM.FormObject.SELECT]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Submit/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Submit/Index.rst
deleted file mode 100644
index e7dc89d511cdbc5dfcd9e1f8ea20800f9893fc47..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Submit/Index.rst
+++ /dev/null
@@ -1,152 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-submit:
-
-======
-SUBMIT
-======
-
-Creates a submit button.
-
-When activated, a submit button submits a form. A form may contain more than
-one submit button.
-
-
-.. _reference-submit-accesskey:
-
-accesskey
-=========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-accesskey`.
-
-
-.. _reference-submit-alt:
-
-alt
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-alt`.
-
-
-.. _reference-submit-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-submit-dir:
-
-dir
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-dir`.
-
-
-.. _reference-submit-disabled:
-
-disabled
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-disabled`.
-
-
-.. _reference-submit-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-id`.
-
-
-.. _reference-submit-label:
-
-label
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-label`.
-
-
-.. _reference-submit-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-lang`.
-
-
-.. _reference-submit-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-submit`
-    specific information.
-
-
-.. _reference-submit-name:
-
-name
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-name`.
-
-
-.. _reference-submit-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-style`.
-
-
-.. _reference-submit-tabindex:
-
-tabindex
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-tabindex`.
-
-
-.. _reference-submit-title:
-
-title
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-title`.
-
-
-.. _reference-submit-type:
-
-type
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-type`.
-
-
-.. _reference-submit-value:
-
-value
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-value`.
-
-[tsref:(cObject).FORM.FormObject.SUBMIT]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Textarea/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Textarea/Index.rst
deleted file mode 100644
index 2c731ec92e4d0241314a996da6c3b9632db51a02..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Textarea/Index.rst
+++ /dev/null
@@ -1,169 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-textarea:
-
-========
-TEXTAREA
-========
-
-The TEXTAREA object creates a multi-line text input control. User agents
-should use the contents of this object as the initial value of the control
-and should render this text initially.
-
-
-.. _reference-textarea-accesskey:
-
-accesskey
-=========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-accesskey`.
-
-
-.. _reference-textarea-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-textarea-cols:
-
-cols
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-cols`.
-
-
-.. _reference-textarea-data:
-
-data
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-data`.
-
-
-.. _reference-textarea-dir:
-
-dir
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-dir`.
-
-
-.. _reference-textarea-disabled:
-
-disabled
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-disabled`.
-
-
-.. _reference-textarea-filters:
-
-filters
-=======
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-filters`.
-
-
-.. _reference-textarea-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-id`.
-
-
-.. _reference-textarea-label:
-
-label
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-label`.
-
-
-.. _reference-textarea-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-lang`.
-
-
-.. _reference-textarea-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-textarea`
-    specific information.
-
-
-.. _reference-textarea-name:
-
-name
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-name`.
-
-
-.. _reference-textarea-readonly:
-
-readonly
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-readonly`.
-
-
-.. _reference-textarea-rows:
-
-rows
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-rows`.
-
-
-.. _reference-textarea-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-style`.
-
-
-.. _reference-textarea-tabindex:
-
-tabindex
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-tabindex`.
-
-
-.. _reference-textarea-title:
-
-title
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-title`.
-
-[tsref:(cObject).FORM.FormObject.TEXTAREA]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Textblock/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Textblock/Index.rst
deleted file mode 100644
index e3e219c4459f9301437623357ff2a3e36b80e1cc..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Textblock/Index.rst
+++ /dev/null
@@ -1,22 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-textblock:
-
-=========
-TEXTBLOCK
-=========
-
-Creates a block of text. This element can be used for a visual separation or
-transportation of content. It is neither displayed on the confirmation page
-nor in the email.
-
-
-.. _reference-textblock-content:
-
-content
-=======
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-content`.
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Objects/Textline/Index.rst b/typo3/sysext/form/Documentation/Configuration/Objects/Textline/Index.rst
deleted file mode 100644
index 905f9a850437d13edf2094ba9b1b9b3b637f4369..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Objects/Textline/Index.rst
+++ /dev/null
@@ -1,185 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-textline:
-
-========
-TEXTLINE
-========
-
-Creates a single-line text input control.
-
-
-.. _reference-textline-accesskey:
-
-accesskey
-=========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-accesskey`.
-
-
-.. _reference-textline-alt:
-
-alt
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-alt`.
-
-
-.. _reference-textline-class:
-
-class
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-class`.
-
-
-.. _reference-textline-dir:
-
-dir
-===
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-dir`.
-
-
-.. _reference-textline-disabled:
-
-disabled
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-disabled`.
-
-
-.. _reference-textline-filters:
-
-filters
-=======
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-filters`.
-
-
-.. _reference-textline-id:
-
-id
-==
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-id`.
-
-
-.. _reference-textline-label:
-
-label
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-label`.
-
-
-.. _reference-textline-lang:
-
-lang
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-lang`.
-
-
-.. _reference-textline-layout:
-
-layout
-======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-layout` and the :ref:`reference-layout-textline`
-    specific information.
-
-
-.. _reference-textline-maxlength:
-
-maxlength
-=========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-maxlength`.
-
-
-.. _reference-textline-name:
-
-name
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-name`.
-
-
-.. _reference-textline-readonly:
-
-readonly
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-readonly`.
-
-
-.. _reference-textline-size:
-
-size
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-size`.
-
-
-.. _reference-textline-style:
-
-style
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-style`.
-
-
-.. _reference-textline-tabindex:
-
-tabindex
-========
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-tabindex`
-
-
-.. _reference-textline-title:
-
-title
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-title`.
-
-
-.. _reference-textline-type:
-
-type
-====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-type`.
-
-
-.. _reference-textline-value:
-
-value
-=====
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-objects-attributes-value`.
-
-[tsref:(cObject).FORM.FormObject.TEXTLINE]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Postprocessors/Index.rst b/typo3/sysext/form/Documentation/Configuration/Postprocessors/Index.rst
deleted file mode 100644
index 10ecace040e3a8d76c8180a2416fc89943b27dad..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Postprocessors/Index.rst
+++ /dev/null
@@ -1,61 +0,0 @@
-.. include:: ../../Includes.txt
-
-
-.. _reference-postprocessors:
-
-==============
-postProcessors
-==============
-
-Add postProcessors to the FORM.
-
-postProcessors define how TYPO3 processes submitted forms after the form is
-rendered according to filters and rules.
-
-Multiple postProcessors are accepted for one FORM object, but you have to
-add these postProcessors one by one.
-
-Currently there are two postProcessors:
-
-.. toctree::
-    :maxdepth: 5
-    :titlesonly:
-    :glob:
-
-    Mail/Index.rst
-    Redirect/Index.rst
-
-The processing will be done in the order of the postProcessors.
-
-Custom postProcessors
-=====================
-
-It is also possible to configure a custom class as a postProcessor. Just use
-the class name as the postProcessor name.
-The postProcessor class should implement `TYPO3\CMS\Form\PostProcess\PostProcessorInterface`
-
-The custom postProcessor is not available within the form wizard. Currently,
-there is no possibility to extend the wizard.
-
-**Example:**
-
-.. code-block:: typoscript
-
-  postProcessor {
-    1 = mail
-    1 {
-      recipientEmail = bar@foo.org
-      senderEmail = foo@bar.com
-      subject = Baz
-    }
-
-    2 = redirect
-    2 {
-      destination = 5
-    }
-
-    3 = Vendor\ExtensionName\Folder\ClassName
-    3 {
-    }
-  }
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Postprocessors/Mail/Index.rst b/typo3/sysext/form/Documentation/Configuration/Postprocessors/Mail/Index.rst
deleted file mode 100644
index 2ecf92029cfd3e9e9aa9a71704b162162834c12a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Postprocessors/Mail/Index.rst
+++ /dev/null
@@ -1,321 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-postprocessors-mail:
-
-====
-mail
-====
-
-The mail postProcessor sends submitted data by mail.
-
-.. _reference-postProcessor-mail-mail:
-
-Mail
-====
-
-Configuration options for the mail to deliver.
-
-
-.. _reference-postprocessors-mail-ccemail:
-
-ccEmail
--------
-
-:aspect:`Property:`
-    ccEmail
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Email address the submitted data is sent to as a carbon copy.
-
-
-.. _reference-postprocessors-mail-organization:
-
-organization
-------------
-
-:aspect:`Property:`
-    organization
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Organization mail header.
-
-
-.. _reference-postprocessors-mail-priority:
-
-priority
---------
-
-:aspect:`Property:`
-    priority
-
-:aspect:`Data type:`
-    integer
-
-:aspect:`Description:`
-    Priority of the email. Integer value between 1 and 5. If the priority is
-    configured, but too high, it will be set to 5, which means very low
-    priority.
-
-:aspect:`Default:`
-    3
-
-
-.. _reference-postprocessors-mail-recipientemail:
-
-recipientEmail
---------------
-
-:aspect:`Property:`
-    recipientEmail
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Email address the submitted data is sent to.
-
-
-.. _reference-postprocessors-mail-senderemail:
-
-senderEmail
------------
-
-:aspect:`Property:`
-    senderEmail
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Email address which is shown as sender of the email (from header).
-
-:aspect:`Default:`
-    TYPO3\_CONF\_VARS['MAIL']['defaultMailFromAddress']
-
-
-.. _reference-postprocessors-mail-senderemailfield:
-
-senderEmailField
-----------------
-
-:aspect:`Property:`
-    senderEmailField
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Name of the form field which holds the sender's email address (from
-    header).
-
-    Normally, you can find the (filtered) name in the HTML output between
-    the square brackets like tx\_form[name] where name is the name of the
-    object.
-
-    Only used if senderEmail is not set.
-
-
-.. _reference-postprocessors-mail-sendername:
-
-senderName
-----------
-
-:aspect:`Property:`
-    senderName
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Name which is shown as sender of the email (from header).
-
-:aspect:`Default:`
-    TYPO3\_CONF\_VARS['MAIL']['defaultMailFromName']
-
-
-.. _reference-postprocessors-mail-sendernamefield:
-
-senderNameField
----------------
-
-:aspect:`Property:`
-    senderNameField
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Name of the form field which holds the sender's name (from header).
-
-    Normally you can find the (filtered) name in the HTML output between the
-    square brackets like tx\_form[name] where name is the name of the
-    object.
-
-    Only used if senderName is not set.
-
-
-.. _reference-form-subject:
-
-subject
--------
-
-:aspect:`Property:`
-    subject
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Subject of the email sent by the form.
-
-:aspect:`Default:`
-    Formmail on 'Your\_HOST'
-
-
-.. _reference-postprocessors-mail-subjectfield:
-
-subjectField
-------------
-
-:aspect:`Property:`
-    subjectField
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Name of the form field which holds the subject.
-
-    Normally you can find the (filtered) name in the HTML output between the
-    square brackets like tx\_form[name] where name is the name of the
-    object.
-
-    Only used if subject is not set.
-
-[tsref:(cObject).FORM->postProcessor.mail]
-
-
-.. _reference-postprocessors-mail-htmlMailTemplatePath:
-
-htmlMailTemplatePath
---------------------
-
-:aspect:`Property:`
-    htmlMailTemplatePath
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Name of the template to use for HTML-Content.
-
-    Default is `Html`. Useful to use multiple Mail Postprocessors with different templates.
-
-
-.. _reference-postprocessors-mail-plaintextMailTemplatePath:
-
-plaintextMailTemplatePath
--------------------------
-
-:aspect:`Property:`
-    plaintextMailTemplatePath
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Name of the template to use for Plaintext-Content.
-
-    Default is `Plain`. Useful to use multiple Mail Postprocessors with different templates.
-
-.. _reference-postProcessor-mail-messages:
-
-Messages
-========
-
-.. _reference-postprocessors-mail-messages-error:
-
-messages.error
---------------
-
-:aspect:`Property:`
-    messages.error
-
-:aspect:`Data type:`
-    string/ cObject
-
-:aspect:`Description:`
-    Overriding the default text of the error message, describing the error.
-
-    When no cObject type is set, the message is a simple string. The value
-    can directly be assigned to the messages.error property. If one needs
-    the functionality of cObjects, just define the message appropriately.
-    Any cObject is allowed.
-
-    For more information about cObjects, take a look in the document TSREF.
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      messages.error = TEXT
-      messages.error {
-        data = LLL:EXT:theme/Resources/Private/Language/Form/locallang.xlf:messagesError
-      }
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      messages.error = Error while submitting form
-
-:aspect:`Description:`
-    *Local language:*"There was an error when sending the form by mail"
-
-
-.. _reference-postprocessors-mail-messages-success:
-
-messages.success
-----------------
-
-:aspect:`Property:`
-    messages.success
-
-:aspect:`Data type:`
-    string/ cObject
-
-:aspect:`Description:`
-    Overriding the default text of the confirmation message.
-
-    When no cObject type is set, the message is a simple string. The value
-    can directly be assigned to the messages.success property. If one needs
-    the functionality of cObjects, just define the message appropriately.
-    Any cObject is allowed.
-
-    For more information about cObjects, take a look in the document TSREF.
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      messages.success = TEXT
-      messages.success {
-        data = LLL:EXT:theme/Resources/Private/Language/Form/locallang.xlf:messagesSuccess
-      }
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      messages.success = Thanks for submitting
-
-:aspect:`Default:`
-    *Local language:*"The form has been sent successfully by mail"
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Postprocessors/Redirect/Index.rst b/typo3/sysext/form/Documentation/Configuration/Postprocessors/Redirect/Index.rst
deleted file mode 100644
index 6fabe9d06b5d33170845051428d1718327b5d368..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Postprocessors/Redirect/Index.rst
+++ /dev/null
@@ -1,26 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-postprocessors-redirect:
-
-========
-redirect
-========
-
-The redirect postProcessor redirects the user to a defined destination.
-
-.. _reference-postprocessors-redirect-destination:
-
-destination
-===========
-
-:aspect:`Property:`
-    destination
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    One can supply a uid of a page (e.g. 5) or a url (e.g. www.typo3.org).
-    The user will be redirected to this destination.
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Alphabetic/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Alphabetic/Index.rst
deleted file mode 100644
index 2f05287cfff00f901d26a734aa2c9388ea492106..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Alphabetic/Index.rst
+++ /dev/null
@@ -1,69 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-alphabetic:
-
-==========
-alphabetic
-==========
-
-Checks if the submitted value only has the characters a-z or A-Z.
-
-
-.. _reference-rules-alphabetic-allowwhitespace:
-
-allowWhiteSpace
-===============
-
-:aspect:`Description:`
-    See general information for  :ref:`reference-validation-attributes-allowwhitespace`.
-
-
-.. _reference-rules-alphabetic-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-alphabetic-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-:aspect:`Default:`
-    *local language:*"The value contains not only alphabetic characters"
-
-
-.. _reference-rules-alphabetic-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-    For this specific rule the default message consists of two parts, the
-    second one will only be added when **allowWhiteSpace** is set. This
-    functionality is not possible when defining an own message as shown
-    below.
-
-:aspect:`Default:`
-    *local language:*"Use alphabetic characters(, whitespace allowed)"
-
-
-.. _reference-rules-alphabetic-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.alphabetic]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Alphanumeric/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Alphanumeric/Index.rst
deleted file mode 100644
index e3b8151170231de9cbc291e5808b598b2e181ef2..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Alphanumeric/Index.rst
+++ /dev/null
@@ -1,69 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-alphanumeric:
-
-============
-alphanumeric
-============
-
-Checks if the submitted value only has the characters a-z, A-Z or 0-9.
-
-
-.. _reference-rules-alphanumeric-allowwhitespace:
-
-allowWhiteSpace
-===============
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-allowwhitespace`.
-
-
-.. _reference-rules-alphanumeric-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-alphanumeric-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-:aspect:`Default:`
-    *local language:*"The value contains not only alphanumeric characters"
-
-
-.. _reference-rules-alphanumeric-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-    For this specific rule the default message consists of two parts, the
-    second one will only be added when **allowWhiteSpace** is set. This
-    functionality is not possible when defining an own message as shown
-    below.
-
-:aspect:`Default:`
-    *local language:*"Use alphanumeric characters(, whitespace allowed)"
-
-
-.. _reference-rules-alphanumeric-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.alphanumeric]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Between/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Between/Index.rst
deleted file mode 100644
index 4a848cf4c17addd289f2a91c66b8a8a67f2ba2cb..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Between/Index.rst
+++ /dev/null
@@ -1,122 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-between:
-
-=======
-between
-=======
-
-Checks if the submitted value is between the given minimum and maximum
-value. By default, minimum and maximum are excluded, but can be included in
-the validation.
-
-
-.. _reference-rules-between-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-between-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-    For this specific rule the default error message consists of two parts,
-    the second one will only be added when **inclusive** is set. This
-    functionality is not possible when defining an own message as shown
-    below.
-    The markers %minimum and %maximum will be replaced with the values set
-    by TypoScript.
-
-:aspect:`Default:`
-    *local language:*"The value is not between %minimum and %maximum(,
-    inclusively)"
-
-
-.. _reference-rules-between-inclusive:
-
-inclusive
-=========
-
-:aspect:`Property:`
-    inclusive
-
-:aspect:`Data type:`
-    boolean
-
-:aspect:`Description:`
-    If inclusive = 1, the minimum and maximum value are included in the
-    comparison.
-
-:aspect:`Default:`
-    0
-
-
-.. _reference-rules-between-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-    For this specific rule the default message consists of two parts, the
-    second one will only be added when **inclusive** is set. This
-    functionality is not possible when defining an own message as shown
-    below.
-    The markers %minimum and %maximum will be replaced with the values set
-    by TypoScript.
-
-:aspect:`Default:`
-    *local language:*"The value must be between %minimum and %maximum(,
-    inclusively)"
-
-
-.. _reference-rules-between-maximum:
-
-maximum
-=======
-
-:aspect:`Property:`
-    maximum
-
-:aspect:`Data type:`
-    integer
-
-:aspect:`Description:`
-    The maximum value of the comparison.
-
-
-.. _reference-rules-between-minimum:
-
-minimum
-=======
-
-:aspect:`Property:`
-    minimum
-
-:aspect:`Data type:`
-    integer
-
-:aspect:`Description:`
-    The minimum value of the comparison.
-
-
-.. _reference-rules-between-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.between]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Date/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Date/Index.rst
deleted file mode 100644
index 4781cc3a4287ad9ac7dd9fea4f6e2786caffe0af..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Date/Index.rst
+++ /dev/null
@@ -1,85 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-date:
-
-====
-date
-====
-
-Checks if the submitted value is a valid date, and the format is equal to
-the one set in TypoScript.
-
-The format configuration is like the PHP strftime() conversion specifiers.
-The message shown to the visitor supports the format as well, but will be
-shown to the visitor in a human readable way.
-%e-%m-%Y becomes d-mm-yyyy in English.
-
-
-.. _reference-rules-date-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-date-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-:aspect:`Default:`
-    *local language:*"The value does not appear to be a valid date"
-
-
-.. _reference-rules-date-format:
-
-format
-======
-
-:aspect:`Property:`
-    format
-
-:aspect:`Data type:`
-    strftime-conf
-
-:aspect:`Description:`
-    The format of the submitted data.
-
-    See the PHP-manual (strftime) for the codes, or datatype "strftime-conf"
-    in the TYPO3 document TSref.
-
-:aspect:`Default:`
-    %e-%m-%Y
-
-
-.. _reference-rules-date-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-    The %format marker will be replaced with a human readable format.
-    %e-%m-%Y becomes d-mm-yyyy in English.
-
-:aspect:`Default:`
-    *local language:*"(%format)"
-
-
-.. _reference-rules-date-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.date]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Digit/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Digit/Index.rst
deleted file mode 100644
index 3aedee4d27f97ce4833821bcb96f3dd38237258c..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Digit/Index.rst
+++ /dev/null
@@ -1,55 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-digit:
-
-=====
-digit
-=====
-
-Checks if the submitted value only has the characters 0-9.
-
-
-.. _reference-rules-digit-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-digit-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-:aspect:`Default:`
-    *local language:*"The value contains not only digit characters"
-
-
-.. _reference-rules-digit-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-:aspect:`Default:`
-    *local language:*"Use digit characters"
-
-
-.. _reference-rules-digit-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.digit]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Email/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Email/Index.rst
deleted file mode 100644
index fdd51d558344e784416d82eab15738b34eeb544d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Email/Index.rst
+++ /dev/null
@@ -1,60 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-email:
-
-=====
-email
-=====
-
-Checks if the submitted value is a valid email address.
-
-Validates an RFC 2822 email address, except does not allow most punctuation
-and non-ascii alphanumeric characters. Also does not take length
-requirements into account. Allows domain name and IP addresses, and ensures
-that the IP address entered is valid.
-
-
-.. _reference-rules-email-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-email-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-:aspect:`Default:`
-    *local language:*"This is not a valid email address"
-
-
-.. _reference-rules-email-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-:aspect:`Default:`
-    *local language:*"(john.doe@domain.com)"
-
-
-.. _reference-rules-email-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.email]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Equals/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Equals/Index.rst
deleted file mode 100644
index ec82581fefa2cbac69dbdde7d0e38833ee8e408f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Equals/Index.rst
+++ /dev/null
@@ -1,80 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-equals:
-
-======
-equals
-======
-
-Compares the submitted data of two FORM objects. If they are not equal, the
-rule does not validate.
-
-The rule and error messages will be put in the label of the object the rule
-is attached with by the property "element".
-
-
-.. _reference-rules-equals-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-equals-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-    The %field marker will be replaces with the property "field".
-
-:aspect:`Default:`
-    *local language:*"The value does not equal the value in field '%field'"
-
-
-.. _reference-rules-equals-field:
-
-field
-=====
-
-:aspect:`Property:`
-    field
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    The name of the object to compare with.
-
-    See explanation of "element" property.
-
-
-.. _reference-rules-equals-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-    The %field marker will be replaces with the property "field".
-
-:aspect:`Default:`
-    *local language:*"This field must be equal to '%field'"
-
-
-.. _reference-rules-equals-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.equals]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Float/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Float/Index.rst
deleted file mode 100644
index 97f02d75c6dc0c4ff9030c48198a13f507a0b1e2..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Float/Index.rst
+++ /dev/null
@@ -1,69 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-float:
-
-=====
-float
-=====
-
-Checks if the submitted value is a floating point number (aka floats,
-doubles or real numbers).
-
-Float depends on your config.locale\_all setting. For German
-(config.locale\_all = de\_DE) one will get the following values (partly)
-with the PHP function localeconv():
-
-- 'decimal\_point' => string '.' Decimal point character
-- 'thousands\_sep' => string '' Thousands separator
-- 'mon\_decimal\_point' => string ',' Monetary decimal point character
-- 'mon\_thousands\_sep' => string '.' Monetary thousands separator
-
-First both thousands separators are deleted from the float, then the decimal
-points are replaced by a dot to get a proper float which PHP can handle
-properly.
-
-
-.. _reference-rules-float-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-float-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-:aspect:`Default:`
-    *local language:*"The value does not appear to be a float"
-
-
-.. _reference-rules-float-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-:aspect:`Default:`
-    *local language:*"Enter a float"
-
-
-.. _reference-rules-float-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.float]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Greaterthan/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Greaterthan/Index.rst
deleted file mode 100644
index e2d7574e3e97d54f9eb8cf63abf5877196a71d5d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Greaterthan/Index.rst
+++ /dev/null
@@ -1,74 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-greaterthan:
-
-===========
-greaterthan
-===========
-
-Checks if the submitted value is greater than the integer set in TypoScript.
-
-
-.. _reference-rules-greaterthan-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-greaterthan-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-    The marker %minimum will be replaced with the value set in TypoScript.
-
-:aspect:`Default:`
-    *local language:*"The value does not appear to be greater than %minimum"
-
-
-.. _reference-rules-greaterthan-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-    The marker %minimum will be replaced with the value set by TypoScript.
-
-:aspect:`Default:`
-    *local language:*"The value must be greater than %minimum"
-
-
-.. _reference-rules-greaterthan-minimum:
-
-minimum
-=======
-
-:aspect:`Property:`
-    minimum
-
-:aspect:`Data type:`
-    integer
-
-:aspect:`Description:`
-    The submitted value must be greater than the minimum value.
-
-
-.. _reference-rules-greaterthan-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.greaterthan]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Inarray/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Inarray/Index.rst
deleted file mode 100644
index 8aa5b07f4756cbc1255b404ee1edd13075dd049c..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Inarray/Index.rst
+++ /dev/null
@@ -1,99 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-inarray:
-
-=======
-inarray
-=======
-
-Compares the submitted value with the values in the array set in TypoScript.
-
-
-.. _reference-rules-inarray-array:
-
-array
-=====
-
-:aspect:`Property:`
-    array
-
-:aspect:`Data type:`
-    [array of numbers]
-
-:aspect:`Description:`
-    The array containing the values which will be compared with the incoming
-    data.
-
-    **Example:**
-
-    .. code-block:: html
-
-      array {
-        1 = TYPO3 4.5 LTS
-        2 = TYPO3 6.2 LTS
-        3 = TYPO3 7 LTS
-      }
-
-
-.. _reference-rules-inarray-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-inarray-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-:aspect:`Default:`
-    *local language:*"The value does not appear to be valid"
-
-
-.. _reference-rules-inarray-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-:aspect:`Default:`
-    *local language:*"Only a few values are possible"
-
-
-.. _reference-rules-inarray-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-
-.. _reference-rules-inarray-strict:
-
-strict
-======
-
-:aspect:`Property:`
-    strict
-
-:aspect:`Data type:`
-    boolean
-
-:aspect:`Description:`
-    The types of the needle in the haystack are also checked if strict = 1.
-
-:aspect:`Default:`
-    0
-
-[tsref:(cObject).FORM->rules.inarray]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Index.rst
deleted file mode 100644
index 37a49aee48f6da69ac79ab776d7f9fa491485939..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Index.rst
+++ /dev/null
@@ -1,78 +0,0 @@
-.. include:: ../../Includes.txt
-
-
-.. _reference-rules:
-
-================
-Validation Rules
-================
-
-Validation rules are a powerful tool to add validation to the form. The
-rules function will always be used at the beginning of the form and belongs
-to the FORM object.
-
-It is possible to have multiple validation rules for one FORM object, but
-the rules have to be added one by one.
-
-**Example**
-
-.. code-block:: typoscript
-
-  rules {
-    1 = required
-    1 (
-      element = first_name
-    )
-    2 = required
-    2 {
-      element = last_name
-      showMessage = 0
-      error = TEXT
-      error {
-        value = Please enter your last name
-      }
-    }
-    3 = required
-    3 {
-      element = email_address
-    }
-    4 = email
-    4 {
-      element = email_address
-    }
-  }
-
-
-When a rule is defined, it will automatically add a message to the object
-the rule is connected with. This message will be shown in the local language
-and will tell the user the input needs to be according to this rule. The
-message can be hidden or overruled with a user defined string/ cObject.
-
-The validation will be done by the order of the rules. The validation can be
-stopped when a certain rule is not valid. By default all validation rules
-will be processed.
-
-.. toctree::
-    :maxdepth: 5
-    :titlesonly:
-    :glob:
-
-    ValidationAttributes/Index.rst
-    Alphabetic/Index.rst
-    Alphanumeric/Index.rst
-    Between/Index.rst
-    Date/Index.rst
-    Digit/Index.rst
-    Email/Index.rst
-    Equals/Index.rst
-    Float/Index.rst
-    Greaterthan/Index.rst
-    Inarray/Index.rst
-    Integer/Index.rst
-    Ip/Index.rst
-    Length/Index.rst
-    Lessthan/Index.rst
-    Regexp/Index.rst
-    Required/Index.rst
-    Uri/Index.rst
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Integer/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Integer/Index.rst
deleted file mode 100644
index 5d94c1e241b7c6742ea8c767a4fb0acf5a573c2d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Integer/Index.rst
+++ /dev/null
@@ -1,55 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-integer:
-
-=======
-integer
-=======
-
-Checks if the submitted value is an integer.
-
-
-.. _reference-rules-integer-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-integer-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-:aspect:`Default:`
-    *local language:*"The value does not appear to be an integer"
-
-
-.. _reference-rules-integer-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-:aspect:`Default:`
-    *local language:*"Use a integer"
-
-
-.. _reference-rules-integer-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.integer]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Ip/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Ip/Index.rst
deleted file mode 100644
index 0d29fac9eef2f8bc3cc0350d113fd6ba78f2a041..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Ip/Index.rst
+++ /dev/null
@@ -1,55 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-ip:
-
-==
-ip
-==
-
-Checks if the submitted value is an IP address.
-
-
-.. _reference-rules-ip-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-ip-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-:aspect:`Default:`
-    *local language:*"The value does not appear to be a valid IP address"
-
-
-.. _reference-rules-ip-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-:aspect:`Default:`
-    *local language:*"(123.123.123.123)"
-
-
-.. _reference-rules-ip-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.ip]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Length/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Length/Index.rst
deleted file mode 100644
index 264e4b9864d917eaa9bd0a107849f0d1f9151923..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Length/Index.rst
+++ /dev/null
@@ -1,103 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-length:
-
-======
-length
-======
-
-Checks if the submitted value is of a certain length. A minimum length can
-be used or a minimum and a maximum length.
-
-
-.. _reference-rules-length-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-length-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-    For this specific rule the default error message consists of two parts,
-    the second one will only be added when **maximum** is set. This
-    functionality is not possible when defining an own message as shown
-    below.
-    The markers %minimum and %maximum will be replaced with the values set
-    by TypoScript.
-
-:aspect:`Default:`
-    *local language:*"The value is less than %minimum characters long
-    (, or longer than %maximum)"
-
-
-.. _reference-rules-length-maximum:
-
-maximum
-=======
-
-:aspect:`Property:`
-    maximum
-
-:aspect:`Data type:`
-    integer
-
-:aspect:`Description:`
-    The maximum length of the submitted value. Maximum can only be used in
-    combination with minimum.
-
-
-.. _reference-rules-length-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-    For this specific rule the default message consists of two parts, the
-    second one will only be added when **maximum** is set. This
-    functionality is not possible when defining an own message as shown
-    below.
-    The markers %minimum and %maximum will be replaced with the values set
-    by TypoScript.
-
-:aspect:`Default:`
-    *local language:*"The length of the value must have a minimum of
-    %minimum characters(, and a maximum of %maximum)"
-
-
-.. _reference-rules-length-minimum:
-
-minimum
-=======
-
-:aspect:`Property:`
-    minimum
-
-:aspect:`Data type:`
-    integer
-
-:aspect:`Description:`
-    The minimum length of the submitted value.
-
-
-.. _reference-rules-length-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.length]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Lessthan/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Lessthan/Index.rst
deleted file mode 100644
index 4c2a479e71fa7fe1ce0ecdd7de81384be9ebb0b3..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Lessthan/Index.rst
+++ /dev/null
@@ -1,74 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-lessthan:
-
-========
-lessthan
-========
-
-Checks if the submitted value is less than the integer set in TypoScript.
-
-
-.. _reference-rules-lessthan-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-lessthan-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-    The marker %maximum will be replaced with the value set in TypoScript.
-
-:aspect:`Default:`
-    *local language:*"The value does not appear to be less than %maximum"
-
-
-.. _reference-rules-lessthan-maximum:
-
-maximum
-=======
-
-:aspect:`Property:`
-    maximum
-
-:aspect:`Data type:`
-    integer
-
-:aspect:`Description:`
-    The submitted value must be less than the maximum value.
-
-
-.. _reference-rules-lessthan-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-    The marker %maximum will be replaced with the value set in TypoScript.
-
-:aspect:`Default:`
-    *local language:*"The value must be less than %maximum"
-
-
-.. _reference-rules-lessthan-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.lessthan]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Regexp/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Regexp/Index.rst
deleted file mode 100644
index cc0a8cbca7fd51d4bd7ed92e4e98eaff6bde6035..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Regexp/Index.rst
+++ /dev/null
@@ -1,73 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-regexp:
-
-======
-regexp
-======
-
-Checks if the submitted value matches your own regular expression, using PHP
-function preg\_match().
-
-
-.. _reference-rules-regexp-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-regexp-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-:aspect:`Default:`
-    *local language:*"The value does not match against pattern"
-
-
-.. _reference-rules-regexp-expression:
-
-expression
-==========
-
-:aspect:`Property:`
-    expression
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    The submitted value needs to match the expression, given in your
-    pattern.
-
-
-.. _reference-rules-regexp-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-:aspect:`Default:`
-    *local language:*"Use the right pattern"
-
-
-
-.. _reference-rules-regexp-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.regexp]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Required/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Required/Index.rst
deleted file mode 100644
index 103e3935b3481f350cbd2c1071bf9f8e719307f8..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Required/Index.rst
+++ /dev/null
@@ -1,57 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-required:
-
-========
-required
-========
-
-Checks if the submitted value exists and is not empty.
-
-0 or "0" are allowed and the rule will return true.
-
-
-.. _reference-rules-required-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-required-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-:aspect:`Default:`
-    *local language:*"This field is required"
-
-
-.. _reference-rules-required-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-:aspect:`Default:`
-    *local language:*"Required"
-
-
-.. _reference-rules-required-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.required]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/Uri/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/Uri/Index.rst
deleted file mode 100644
index 43d0cc37b1e67ffc10cbea265747d923fbc3c5af..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/Uri/Index.rst
+++ /dev/null
@@ -1,58 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-rules-uri:
-
-===
-uri
-===
-
-This validation rule checks on a URI, which can include all of the
-following:
-
-- scheme://usern:passw@domain:port/path/file.ext?querystring#fragment
-
-
-.. _reference-rules-uri-element:
-
-element
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-element`.
-
-
-.. _reference-rules-uri-error:
-
-error
-=====
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-error`.
-
-:aspect:`Default:`
-    *local language:*"The value does not appear to be a hostname"
-
-
-.. _reference-rules-uri-message:
-
-message
-=======
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-message`.
-
-:aspect:`Default:`
-    *local language:*"The value must be a hostname"
-
-
-.. _reference-rules-uri-showmessage:
-
-showMessage
-===========
-
-:aspect:`Description:`
-    See general information for :ref:`reference-validation-attributes-showmessage`.
-
-[tsref:(cObject).FORM->rules.uri]
-
diff --git a/typo3/sysext/form/Documentation/Configuration/Rules/ValidationAttributes/Index.rst b/typo3/sysext/form/Documentation/Configuration/Rules/ValidationAttributes/Index.rst
deleted file mode 100644
index 93e4347018c8bf092db89b6c60190b2b1dbc1667..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Configuration/Rules/ValidationAttributes/Index.rst
+++ /dev/null
@@ -1,148 +0,0 @@
-.. include:: ../../../Includes.txt
-
-
-.. _reference-validation-attributes:
-
-=====================
-Validation Attributes
-=====================
-
-.. contents::
-    :local:
-    :depth: 1
-
-
-.. _reference-validation-attributes-allowwhitespace:
-
-allowWhiteSpace
-===============
-
-:aspect:`Property:`
-    allowWhiteSpace
-
-:aspect:`Data type:`
-    boolean
-
-:aspect:`Description:`
-    If allowWhiteSpace = 1, whitespace is allowed in front of, after or
-    between the characters.
-
-:aspect:`Default:`
-    0
-
-
-.. _reference-validation-attributes-element:
-
-element
-=======
-
-:aspect:`Property:`
-    element
-
-:aspect:`Data type:`
-    string
-
-:aspect:`Description:`
-    Name of the object. Normally the "filtered" name can be found in the
-    HTML output between the square brackets like tx\_form[name] where "name"
-    is the name of the object.
-
-
-.. _reference-validation-attributes-error:
-
-error
-=====
-
-:aspect:`Property:`
-    error
-
-:aspect:`Data type:`
-    string/ cObject
-
-:aspect:`Description:`
-    Overriding the default text of the error message, describing the error.
-
-    When no cObject type is set, the message is a simple string. The value
-    can directly be assigned to the message property. If one needs the
-    functionality of cObjects, just define the message appropriately. Any
-    cObject is allowed.
-
-    For more information about cObjects, take a look in the document TSREF.
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      error = TEXT
-      error {
-        data = LLL:EXT:theme/Resources/Private/Language/Form/locallang.xlf:alphabeticError
-      }
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      error = The value contains not only alphabetic characters
-
-:aspect:`Default:`
-    Depends on the rule. Check over there.
-
-
-.. _reference-validation-attributes-message:
-
-message
-=======
-
-:aspect:`Property:`
-    message
-
-:aspect:`Data type:`
-    string/ cObject
-
-:aspect:`Description:`
-    Overriding the default text of the message, describing the rule.
-
-    When no cObject type is set, the message is a simple string. The value
-    can directly be assigned to the message property. If one needs the
-    functionality of cObjects, just define the message appropriately. Any
-    cObject is allowed.
-
-    For more information about cObjects, take a look in the document TSREF.
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      message = TEXT
-      message {
-        data = LLL:EXT:theme/Resources/Private/Language/Form/locallang.xlf:betweenMessage
-      }
-
-    **Example:**
-
-    .. code-block:: typoscript
-
-      message =  The value must be between %minimum and %maximum
-
-:aspect:`Default:`
-    Depends on the rule. Check over there.
-
-
-.. _reference-validation-attributes-showmessage:
-
-showMessage
-===========
-
-:aspect:`Property:`
-    showMessage
-
-:aspect:`Data type:`
-    boolean
-
-:aspect:`Description:`
-    If showMessage = 0, a message describing the rule will not be added to
-    the label of the object.
-
-:aspect:`Default:`
-    1
-
diff --git a/typo3/sysext/form/Documentation/Images/FormCreationWizard.png b/typo3/sysext/form/Documentation/Images/FormCreationWizard.png
deleted file mode 100644
index 2256bbc51c0a4019f45db0757cae217d64fbd88c..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Documentation/Images/FormCreationWizard.png and /dev/null differ
diff --git a/typo3/sysext/form/Documentation/Images/FormCreationWizardElementsTab.png b/typo3/sysext/form/Documentation/Images/FormCreationWizardElementsTab.png
deleted file mode 100644
index c3478cb504f6f91f51781d6396b02f43a5f6688f..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Documentation/Images/FormCreationWizardElementsTab.png and /dev/null differ
diff --git a/typo3/sysext/form/Documentation/Images/FormCreationWizardFormTab.png b/typo3/sysext/form/Documentation/Images/FormCreationWizardFormTab.png
deleted file mode 100644
index 02bcb573374073be78f922b97e6d0aabd476c59c..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Documentation/Images/FormCreationWizardFormTab.png and /dev/null differ
diff --git a/typo3/sysext/form/Documentation/Images/FormCreationWizardOptionsTab.png b/typo3/sysext/form/Documentation/Images/FormCreationWizardOptionsTab.png
deleted file mode 100644
index 22a3affa1a8dfd3003d3cfc365841af60b0babb2..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Documentation/Images/FormCreationWizardOptionsTab.png and /dev/null differ
diff --git a/typo3/sysext/form/Documentation/Images/FormCreationWizardShowTabs.png b/typo3/sysext/form/Documentation/Images/FormCreationWizardShowTabs.png
deleted file mode 100644
index 0195c2f99f88429222a51c882eeb28bee25d01b7..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Documentation/Images/FormCreationWizardShowTabs.png and /dev/null differ
diff --git a/typo3/sysext/form/Documentation/Includes.txt b/typo3/sysext/form/Documentation/Includes.txt
deleted file mode 100644
index efbb82abf298298edbc9364bd4eac44ee59b46b4..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Includes.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-.. This is 'Includes.txt'. It is included at the very top of each and
-    every ReST source file in THIS documentation project (= manual).
-
-.. role:: aspect(emphasis)
-.. role:: html(code)
-.. role:: js(code)
-.. role:: php(code)
-.. role:: typoscript(code)
-.. role:: ts(typoscript)
-    :class: typoscript
-
-.. highlight:: php
-.. default-role:: code
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Index.rst b/typo3/sysext/form/Documentation/Index.rst
deleted file mode 100644
index 7edcdb088cd3b8493bba69c479fab30291e55a1b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Index.rst
+++ /dev/null
@@ -1,56 +0,0 @@
-.. include:: Includes.txt
-
-
-.. _start:
-
-====
-Form
-====
-
-:Extension key:
-    form
-
-:Version:
-    8
-
-:Language:
-    en
-
-:Description:
-    Form Library, Plugin and Wizard
-
-:Keywords:
-    form
-
-:Copyright:
-    2000-2016
-
-:Author:
-    TYPO3 CMS Core Development Team
-
-:License:
-    Open Content License available from `www.opencontent.org/opl.shtml
-    <http://www.opencontent.org/opl.shtml>`_
-
-:Rendered:
-    |today|
-
-The content of this document is related to TYPO3,
-
-a GNU/GPL CMS/Framework available from `www.typo3.org
-<http://www.typo3.org/>`_
-
-
-
-
-**Table of Contents**
-
-.. toctree::
-    :maxdepth: 5
-    :titlesonly:
-    :glob:
-
-    Introduction/Index
-    Administration/Index
-    Configuration/Index
-    Targets
diff --git a/typo3/sysext/form/Documentation/Introduction/Index.rst b/typo3/sysext/form/Documentation/Introduction/Index.rst
deleted file mode 100644
index fc1a6b6182502b806d922768994e9d03ec61d734..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Introduction/Index.rst
+++ /dev/null
@@ -1,30 +0,0 @@
-.. include:: ../Includes.txt
-
-
-.. _introduction:
-
-============
-Introduction
-============
-
-
-.. _what-does-it-do:
-
-What does it do?
-================
-
-This extension allows editors to easily build forms using a drag and drop
-interface. A WYSIWYG view simplifies the process of building a form, and
-relatively non-technical editors can easily add chained validation rules
-on a field-by-field basis (e.g., email and/ or alphanumeric validation).
-Furthermore, filters can be added to each field to manipulate the entered
-form data.
-
-Experienced integrators do not have to use the wizard. Instead, the form
-configuration can be created just using a TypoScript like syntax.
-
-.. figure:: ../Images/FormCreationWizard.png
-    :alt: The form wizard with some predefined form elements.
-
-The screenshot shows the form wizard with some predefined form elements.
-
diff --git a/typo3/sysext/form/Documentation/Settings.cfg b/typo3/sysext/form/Documentation/Settings.cfg
deleted file mode 100644
index bcc46bc7d96100c451d52644e673e3daa3cd8d72..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Settings.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
-[general]
-
-project     = Form Library, Plugin and Wizard
-version     = 8
-release     = 8
-t3author    = Patrick Broens, Ralf Zimmermann
-copyright   = 1997-2016
-
-description = This is the documentation of TYPO3's system
-      extension 'form'. This extension brings along the
-      content element 'form' and a wizard.
-
-
-[html_theme_options]
-
-project_issues       = https://forge.typo3.org/projects/typo3cms-core/issues
-project_repository   = https://git.typo3.org/Packages/TYPO3.CMS.git
diff --git a/typo3/sysext/form/Documentation/Targets.rst b/typo3/sysext/form/Documentation/Targets.rst
deleted file mode 100644
index 8b5ef39fa6a11f822a8b5f792a201b683eb6614f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Targets.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-.. include:: Includes.txt
-
-.. _index-labels-for-crossreferencing:
-
-==================================
-Index: Labels for Crossreferencing
-==================================
-
-.. ref-targets-list::
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/button.txt b/typo3/sysext/form/Documentation/Tests/Attributes/button.txt
deleted file mode 100644
index 2087507751b20675d708b0b0a5bc54d29660529d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/button.txt
+++ /dev/null
@@ -1,205 +0,0 @@
-form.attributes.button = FORM
-form.attributes.button {
-	method = post
-
-	# Label test
-	10 = FIELDSET
-	10 {
-		legend = Label test
-		10 = BUTTON
-		10 {
-			label = label
-		}
-		20 = BUTTON
-		20 {
-			label.value = label.value
-		}
-		30 = BUTTON
-		30 {
-			label = TEXT
-			label {
-				value = TEXT cObj
-			}
-		}
-	}
-
-	# Layout test
-	20 = FIELDSET
-	20 {
-		legend = Layout test
-		10 = BUTTON
-		10 {
-			label = label in front of input (default)
-		}
-		20 = BUTTON
-		20 {
-			layout (
-				<input />
-				<label />
-			)
-			label = label after input
-		}
-		30 = BUTTON
-		30 {
-			layout = <input />
-			value = No label
-		}
-	}
-
-	# Accesskey
-	30 = FIELDSET
-	30 {
-		legend = Accesskey test
-		10 = BUTTON
-		10 {
-			label = This button has an accesskey
-			accesskey = a
-		}
-	}
-
-	# Alt
-	40 = FIELDSET
-	40 {
-		legend = Alt test
-		10 = BUTTON
-		10 {
-			label = This button has an alt attribute
-			alt = This is the alt attribute content
-		}
-	}
-
-	# Class
-	50 = FIELDSET
-	50 {
-		legend = Class test
-		10 = BUTTON
-		10 {
-			label = This button has a class attribute
-			class = classAtribute
-		}
-		20 = BUTTON
-		20 {
-			label = Multiple classes
-			class = class1 class2
-		}
-	}
-
-	# Dir
-	60 = FIELDSET
-	60 {
-		legend = Dir test
-		10 = BUTTON
-		10 {
-			label = Dir ltr
-			dir = ltr
-		}
-		20 = BUTTON
-		20 {
-			label = Dir rtl
-			dir = rtl
-		}
-		30 = BUTTON
-		30 {
-			label = Wrong input in dir
-			dir = abc
-		}
-	}
-
-	# Disabled
-	70 = FIELDSET
-	70 {
-		legend = Disabled test
-		10 = BUTTON
-		10 {
-			label = disabled=1
-			disabled = 1
-		}
-		20 = BUTTON
-		20 {
-			label = disabled=0
-			disabled = 0
-		}
-		30 = BUTTON
-		30 {
-			label = disabled=disabled
-			disabled = disabled
-		}
-	}
-
-	# Id
-	80 = FIELDSET
-	80 {
-		legend = Id test
-		10 = BUTTON
-		10 {
-			label = This button has an id attribute and the label a for attribute
-			id = buttonId
-		}
-	}
-
-	# Lang
-	90 = FIELDSET
-	90 {
-		legend = Lang test
-		10 = BUTTON
-		10 {
-			label = This button has a lang attribute
-			lang = en-US
-		}
-	}
-
-	# Name
-	100 = FIELDSET
-	100 {
-		legend = Name test
-		10 = BUTTON
-		10 {
-			label = This button has a name attribute
-			name = buttonName
-		}
-	}
-
-	# Style
-	110 = FIELDSET
-	110 {
-		legend = style test
-		10 = BUTTON
-		10 {
-			label = This button has a style attribute
-			style = border: 1px solid #000000
-		}
-	}
-
-	# Tabindex
-	120 = FIELDSET
-	120 {
-		legend = Tabindex test
-		10 = BUTTON
-		10 {
-			label = This button has a tabindex attribute
-			tabindex = 1
-		}
-	}
-
-	# Title
-	130 = FIELDSET
-	130 {
-		legend = Title test
-		10 = BUTTON
-		10 {
-			label = This button has a title attribute
-			title = This is the title text
-		}
-	}
-
-	# Value
-	140 = FIELDSET
-	140 {
-		legend = Value test
-		10 = BUTTON
-		10 {
-			label = This button has a value attribute
-			value = Don't you dare to push this button
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/checkbox.txt b/typo3/sysext/form/Documentation/Tests/Attributes/checkbox.txt
deleted file mode 100644
index e169068b60689a79fb74bf67fcff00ae44ff4f4b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/checkbox.txt
+++ /dev/null
@@ -1,226 +0,0 @@
-form.attributes.checkbox = FORM
-form.attributes.checkbox {
-	method = post
-
-	# Label test
-	10 = FIELDSET
-	10 {
-		legend = Label test
-		10 = CHECKBOX
-		10 {
-			label = label
-		}
-		20 = CHECKBOX
-		20 {
-			label.value = label.value
-		}
-		30 = CHECKBOX
-		30 {
-			label = TEXT
-			label {
-				value = TEXT cObj
-			}
-		}
-	}
-
-	# Layout test
-	20 = FIELDSET
-	20 {
-		legend = Layout test
-		10 = CHECKBOX
-		10 {
-			label = label in front of input (default)
-		}
-		20 = CHECKBOX
-		20 {
-			layout (
-				<input />
-				<label />
-			)
-			label = label after input
-		}
-		30 = CHECKBOX
-		30 {
-			layout = <input />
-			value = No label
-		}
-	}
-
-	# Accesskey
-	30 = FIELDSET
-	30 {
-		legend = Accesskey test
-		10 = CHECKBOX
-		10 {
-			label = This checkbox has an accesskey
-			accesskey = a
-		}
-	}
-
-	# Alt
-	40 = FIELDSET
-	40 {
-		legend = Alt test
-		10 = CHECKBOX
-		10 {
-			label = This checkbox has an alt attribute
-			alt = This is the alt attribute content
-		}
-	}
-
-	# Checked
-	50 = FIELDSET
-	50 {
-		legend = Checked test
-		10 = CHECKBOX
-		10 {
-			label = checked=1
-			checked = 1
-		}
-		20 = CHECKBOX
-		20 {
-			label = checked=0
-			checked = 0
-		}
-		30 = CHECKBOX
-		30 {
-			label = checked=checked
-			checked = checked
-		}
-	}
-
-	# Class
-	60 = FIELDSET
-	60 {
-		legend = Class test
-		10 = CHECKBOX
-		10 {
-			label = This checkbox has a class attribute
-			class = classAtribute
-		}
-		20 = CHECKBOX
-		20 {
-			label = Multiple classes
-			class = class1 class2
-		}
-	}
-
-	# Dir
-	70 = FIELDSET
-	70 {
-		legend = Dir test
-		10 = CHECKBOX
-		10 {
-			label = Dir ltr
-			dir = ltr
-		}
-		20 = CHECKBOX
-		20 {
-			label = Dir rtl
-			dir = rtl
-		}
-		30 = CHECKBOX
-		30 {
-			label = Wrong input in dir
-			dir = abc
-		}
-	}
-
-	# Disabled
-	80 = FIELDSET
-	80 {
-		legend = Disabled test
-		10 = CHECKBOX
-		10 {
-			label = disabled=1
-			disabled = 1
-		}
-		20 = CHECKBOX
-		20 {
-			label = disabled=0
-			disabled = 0
-		}
-		30 = CHECKBOX
-		30 {
-			label = disabled=disabled
-			disabled = disabled
-		}
-	}
-
-	# Id
-	90 = FIELDSET
-	90 {
-		legend = Id test
-		10 = CHECKBOX
-		10 {
-			label = This checkbox has an id attribute and the label a for attribute
-			id = checkboxId
-		}
-	}
-
-	# Lang
-	100 = FIELDSET
-	100 {
-		legend = Lang test
-		10 = CHECKBOX
-		10 {
-			label = This checkbox has a lang attribute
-			lang = en-US
-		}
-	}
-
-	# Name
-	110 = FIELDSET
-	110 {
-		legend = Name test
-		10 = CHECKBOX
-		10 {
-			label = This checkbox has a name attribute
-			name = checkboxName
-		}
-	}
-
-	# Style
-	120 = FIELDSET
-	120 {
-		legend = style test
-		10 = CHECKBOX
-		10 {
-			label = This checkbox has a style attribute
-			style = width: 4em; height: 4em;
-		}
-	}
-
-	# Tabindex
-	130 = FIELDSET
-	130 {
-		legend = Tabindex test
-		10 = CHECKBOX
-		10 {
-			label = This checkbox has a tabindex attribute
-			tabindex = 1
-		}
-	}
-
-	# Title
-	140 = FIELDSET
-	140 {
-		legend = Title test
-		10 = CHECKBOX
-		10 {
-			label = This checkbox has a title attribute
-			title = This is the title text
-		}
-	}
-
-	# Value
-	150 = FIELDSET
-	150 {
-		legend = Value test
-		10 = CHECKBOX
-		10 {
-			label = This checkbox has a value attribute
-			value = checkboxValue
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/checkboxgroup.txt b/typo3/sysext/form/Documentation/Tests/Attributes/checkboxgroup.txt
deleted file mode 100644
index 16544eb0554d4dc6c8999d8f27e96cb9c5753b83..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/checkboxgroup.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-form.attributes.checkboxgroup = FORM
-form.attributes.checkboxgroup {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = checkboxgroup
-		}
-	}
-
-	10 = CHECKBOXGROUP
-	10 {
-		legend = Checkbox Group test
-		name = checkboxgroup
-
-		10 = CHECKBOX
-		10 {
-			label = Option 1
-		}
-		20 = CHECKBOX
-		20 {
-			label = Option 2
-		}
-		30 = CHECKBOX
-		30 {
-			label = Option 3
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/fieldset.txt b/typo3/sysext/form/Documentation/Tests/Attributes/fieldset.txt
deleted file mode 100644
index 35b2cc8cbd56d4079afe3a1b578c34e831f1c499..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/fieldset.txt
+++ /dev/null
@@ -1,95 +0,0 @@
-form.attributes.fieldset = FORM
-form.attributes.fieldset {
-	method = post
-
-	# Legend
-	10 = FIELDSET
-	10 {
-		legend = Legend test
-		10 = FIELDSET
-		10 {
-			legend = legend
-		}
-		20 = FIELDSET
-		20 {
-			legend.value = legend.value
-		}
-		30 = FIELDSET
-		30 {
-			legend = TEXT
-			legend {
-				value = TEXT
-			}
-		}
-	}
-
-	# Layout
-	20 = FIELDSET
-	20 {
-		legend = Layout test
-		10 = FIELDSET
-		10 {
-			legend = This should be at the bottom in the HTML source
-			layout (
-				<fieldset>
-				<containerWrap />
-				<legend />
-				</fieldset>
-			)
-			10 = BUTTON
-		}
-	}
-
-	# Class
-	30 = FIELDSET
-	30 {
-		legend = Class test
-		10 = FIELDSET
-		10 {
-			legend = One class
-			class = fieldsetClass
-		}
-		20 = FIELDSET
-		20 {
-			legend = Multiple classes
-			class = fieldsetClass1 fieldsetClass2
-		}
-	}
-
-	# Dir
-	40 = FIELDSET
-	40 {
-		legend = Dir test
-		10 = FIELDSET
-		10 {
-			legend = ltr
-			dir = ltr
-		}
-		20 = FIELDSET
-		20 {
-			legend = rtl
-			dir = rtl
-		}
-	}
-
-	# Id
-	50 = FIELDSET
-	50 {
-		legend = Id test
-		id = fieldsetId
-	}
-
-	# Lang
-	60 = FIELDSET
-	60 {
-		legend = Lang test
-		lang = en-US
-	}
-
-	# Style
-	70 = FIELDSET
-	70 {
-		legend = Style test
-		style = background-color: red;
-	}
-}
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/hidden.txt b/typo3/sysext/form/Documentation/Tests/Attributes/hidden.txt
deleted file mode 100644
index 3e00780af3524ecd8550eeaa253a98a9c9d34039..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/hidden.txt
+++ /dev/null
@@ -1,76 +0,0 @@
-form.attributes.hidden = FORM
-form.attributes.hidden {
-	method = post
-
-	# Class
-	10 = FIELDSET
-	10 {
-		legend = Class test
-		10 = FIELDSET
-		10 {
-			legend = Single class
-			10 = HIDDEN
-			10 {
-				class = hiddenClass
-			}
-		}
-		20 = FIELDSET
-		20 {
-			legend = Multiple classes
-			10 = HIDDEN
-			10 {
-				class = hiddenClass1 hiddenClass2
-			}
-		}
-	}
-
-	# Id
-	20 = FIELDSET
-	20 {
-		legend = Id test
-		10 = HIDDEN
-		10 {
-			id = hiddenId
-		}
-	}
-
-	# Lang
-	30 = FIELDSET
-	30 {
-		legend = Lang test
-		10 = HIDDEN
-		10 {
-			lang = en-US
-		}
-	}
-
-	# Name
-	40 = FIELDSET
-	40 {
-		legend = Name test
-		10 = HIDDEN
-		10 {
-			name = hiddenName
-		}
-	}
-
-	# Style
-	50 = FIELDSET
-	50 {
-		legend = Style test
-		10 = HIDDEN
-		10 {
-			style = background-color: red;
-		}
-	}
-
-	# Value
-	60 = FIELDSET
-	60 {
-		legend = Value test
-		10 = HIDDEN
-		10 {
-			value = hiddenValue
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/optgroup.txt b/typo3/sysext/form/Documentation/Tests/Attributes/optgroup.txt
deleted file mode 100644
index fe79cc9482f93600a4922b2b59449cafb90a5c43..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/optgroup.txt
+++ /dev/null
@@ -1,172 +0,0 @@
-form.attributes.optgroup = FORM
-form.attributes.optgroup {
-	method = post
-
-	# Basics
-	10 = FIELDSET
-	10 {
-		legend = Basics, already shows label
-		10 = SELECT
-		10 {
-			1 = OPTGROUP
-			1 {
-				label = Option Group 1
-				1 = OPTION
-				1 {
-					data = optgroup 1 option 1
-				}
-				2 = OPTION
-				2 {
-					data = optgroup 1 option 2
-				}
-			}
-			2 = OPTGROUP
-			2 {
-				label = Option Group 2
-				1 = OPTION
-				1 {
-					data = optgroup 2 option 1
-				}
-				2 = OPTION
-				2 {
-					data = optgroup 2 option 2
-				}
-			}
-		}
-	}
-
-	# Class
-	20 = FIELDSET
-	20 {
-		legend = Class
-		10 = SELECT
-		10 {
-			1 = OPTGROUP
-			1 {
-				label = Single Class
-				class = singleClass
-				1 = OPTION
-				1 {
-					data = optgroup 1 option 1
-				}
-			}
-			2 = OPTGROUP
-			2 {
-				label = Multiple classes
-				class = class1 class2
-				1 = OPTION
-				1 {
-					data = optgroup 2 option 1
-				}
-			}
-		}
-	}
-
-	# Disabled
-	30 = FIELDSET
-	30 {
-		legend = Disabled
-		10 = SELECT
-		10 {
-			1 = OPTGROUP
-			1 {
-				label = disabled=1
-				disabled = 1
-				1 = OPTION
-				1 {
-					data = optgroup 1 option 1
-				}
-			}
-			2 = OPTGROUP
-			2 {
-				label = disabled=0
-				disabled = 0
-				1 = OPTION
-				1 {
-					data = optgroup 2 option 1
-				}
-			}
-			3 = OPTGROUP
-			3 {
-				label = disabled=disabled
-				disabled = disabled
-				1 = OPTION
-				1 {
-					data = optgroup 3 option 1
-				}
-			}
-		}
-	}
-
-	# Id
-	40 = FIELDSET
-	40 {
-		legend = Id
-		10 = SELECT
-		10 {
-			1 = OPTGROUP
-			1 {
-				label = Option group 1
-				id = optgroup1
-				1 = OPTION
-				1 {
-					data = optgroup 1 option 1
-				}
-			}
-		}
-	}
-
-	# Lang
-	50 = FIELDSET
-	50 {
-		legend = Lang
-		10 = SELECT
-		10 {
-			1 = OPTGROUP
-			1 {
-				label = has Lang
-				lang = en-US
-				1 = OPTION
-				1 {
-					data = optgroup 1 option 1
-				}
-			}
-		}
-	}
-
-	# Style
-	60 = FIELDSET
-	60 {
-		legend = Style
-		10 = SELECT
-		10 {
-			1 = OPTGROUP
-			1 {
-				label = has Style
-				style = background-color: red;
-				1 = OPTION
-				1 {
-					data = optgroup 1 option 1
-				}
-			}
-		}
-	}
-
-	# Title
-	70 = FIELDSET
-	70 {
-		legend = Title
-		10 = SELECT
-		10 {
-			1 = OPTGROUP
-			1 {
-				label = has Title
-				title = This is the OPTGROUP title
-				1 = OPTION
-				1 {
-					data = optgroup 1 option 1
-				}
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/option.txt b/typo3/sysext/form/Documentation/Tests/Attributes/option.txt
deleted file mode 100644
index d79cf77ddd97399c56adc2ccbb1ed06e46b9b62b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/option.txt
+++ /dev/null
@@ -1,176 +0,0 @@
-form.attributes.option = FORM
-form.attributes.option {
-	method = post
-
-	# Data
-	10 = FIELDSET
-	10 {
-		legend = Data
-		10 = SELECT
-		10 {
-			1 = OPTION
-			1 {
-				data = optionData
-			}
-		}
-	}
-
-	# Class
-	20 = FIELDSET
-	20 {
-		legend = Class
-		10 = SELECT
-		10 {
-			1 = OPTION
-			1 {
-				data = Single class
-				class = singleClass
-			}
-			2 = OPTION
-			2 {
-				data = Multiple classes
-				class = class1 class2
-			}
-		}
-	}
-
-	# Disabled
-	30 = FIELDSET
-	30 {
-		legend = Disabled
-		10 = SELECT
-		10 {
-			1 = OPTION
-			1 {
-				data = disabled=1
-				disabled = 1
-			}
-			2 = OPTION
-			2 {
-				data = disabled=0
-				disabled = 0
-			}
-			3 = OPTION
-			3 {
-				data = disabled=disabled
-				disabled = disabled
-			}
-		}
-	}
-
-	# Id
-	40 = FIELDSET
-	40 {
-		legend = Id
-		10 = SELECT
-		10 {
-			1 = OPTION
-			1 {
-				data = optionData
-				id = optionId
-			}
-		}
-	}
-
-	# Label
-	50 = FIELDSET
-	50 {
-		legend = Label
-		10 = SELECT
-		10 {
-			1 = OPTION
-			1 {
-				data = This is a long data text
-				label = short
-			}
-		}
-	}
-
-	# Lang
-	60 = FIELDSET
-	60 {
-		legend = Lang
-		10 = SELECT
-		10 {
-			1 = OPTION
-			1 {
-				data = optionData
-				lang = en-US
-			}
-		}
-	}
-
-	# Selected
-	70 = FIELDSET
-	70 {
-		legend = Selected
-		10 = SELECT
-		10 {
-			1 = OPTION
-			1 {
-				data = selected=0
-				selected = 0
-			}
-			2 = OPTION
-			2 {
-				data = selected=1
-				selected = 1
-			}
-		}
-		20 = SELECT
-		20 {
-			1 = OPTION
-			1 {
-				data = selected=0
-				selected = 0
-			}
-			2 = OPTION
-			2 {
-				data = selected=selected
-				selected = selected
-			}
-		}
-	}
-
-	# Style
-	80 = FIELDSET
-	80 {
-		legend = Style
-		10 = SELECT
-		10 {
-			1 = OPTION
-			1 {
-				data = optionData
-				style = height: 4em;
-			}
-		}
-	}
-
-	# Title
-	90 = FIELDSET
-	90 {
-		legend = Title
-		10 = SELECT
-		10 {
-			1 = OPTION
-			1 {
-				data = optionData
-				title = This is the option title
-			}
-		}
-	}
-
-	# Value
-	100 = FIELDSET
-	100 {
-		legend = Value
-		10 = SELECT
-		10 {
-			1 = OPTION
-			1 {
-				data = optionData
-				value = This is the option value
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/password.txt b/typo3/sysext/form/Documentation/Tests/Attributes/password.txt
deleted file mode 100644
index 7bc66fab1002862d1c204f15e64d3eb25db894b3..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/password.txt
+++ /dev/null
@@ -1,251 +0,0 @@
-form.attributes.password = FORM
-form.attributes.password {
-	method = post
-
-	# Label test
-	10 = FIELDSET
-	10 {
-		legend = Label test
-		10 = PASSWORD
-		10 {
-			label = label
-		}
-		20 = PASSWORD
-		20 {
-			label.value = label.value
-		}
-		30 = PASSWORD
-		30 {
-			label = TEXT
-			label {
-				value = TEXT cObj
-			}
-		}
-	}
-
-	# Layout test
-	20 = FIELDSET
-	20 {
-		legend = Layout test
-		10 = PASSWORD
-		10 {
-			label = label in front of input (default)
-		}
-		20 = PASSWORD
-		20 {
-			layout (
-				<input />
-				<label />
-			)
-			label = label after input
-		}
-		30 = PASSWORD
-		30 {
-			layout = <input />
-			value = No label
-		}
-	}
-
-	# Accesskey
-	30 = FIELDSET
-	30 {
-		legend = Accesskey test
-		10 = PASSWORD
-		10 {
-			label = This field has an accesskey
-			accesskey = a
-		}
-	}
-
-	# Alt
-	40 = FIELDSET
-	40 {
-		legend = Alt test
-		10 = PASSWORD
-		10 {
-			label = This field has an alt attribute
-			alt = This is the alt attribute content
-		}
-	}
-
-	# Class
-	50 = FIELDSET
-	50 {
-		legend = Class test
-		10 = PASSWORD
-		10 {
-			label = This field has a class attribute
-			class = classAtribute
-		}
-		20 = PASSWORD
-		20 {
-			label = Multiple classes
-			class = class1 class2
-		}
-	}
-
-	# Dir
-	60 = FIELDSET
-	60 {
-		legend = Dir test
-		10 = PASSWORD
-		10 {
-			label = Dir ltr
-			dir = ltr
-		}
-		20 = PASSWORD
-		20 {
-			label = Dir rtl
-			dir = rtl
-		}
-		30 = PASSWORD
-		30 {
-			label = Wrong input in dir
-			dir = abc
-		}
-	}
-
-	# Disabled
-	70 = FIELDSET
-	70 {
-		legend = Disabled test
-		10 = PASSWORD
-		10 {
-			label = disabled=1
-			disabled = 1
-		}
-		20 = PASSWORD
-		20 {
-			label = disabled=0
-			disabled = 0
-		}
-		30 = PASSWORD
-		30 {
-			label = disabled=disabled
-			disabled = disabled
-		}
-	}
-
-	# Id
-	80 = FIELDSET
-	80 {
-		legend = Id test
-		10 = PASSWORD
-		10 {
-			label = This field has an id attribute and the label a for attribute
-			id = passwordId
-		}
-	}
-
-	# Lang
-	90 = FIELDSET
-	90 {
-		legend = Lang test
-		10 = PASSWORD
-		10 {
-			label = This field has a lang attribute
-			lang = en-US
-		}
-	}
-
-	# Maxlength
-	95 = FIELDSET
-	95 {
-		legend = Maxlength test
-		10 = PASSWORD
-		10 {
-			label = This field has a maxlength attribute
-			maxlength = 10
-		}
-	}
-
-	# Name
-	100 = FIELDSET
-	100 {
-		legend = Name test
-		10 = PASSWORD
-		10 {
-			label = This field has a name attribute
-			name = passwordName
-		}
-	}
-
-	# Readonly
-	103 = FIELDSET
-	103 {
-		legend = Readonly test
-		10 = PASSWORD
-		10 {
-			label = readonly=1
-			readonly = 1
-			value = thevalue
-		}
-		20 = PASSWORD
-		20 {
-			label = readonly=0
-			readonly = 0
-			value = thevalue
-		}
-		30 = PASSWORD
-		30 {
-			label = readonly=readonly
-			readonly = readonly
-			value = thevalue
-		}
-	}
-
-	# Size
-	106 = FIELDSET
-	106 {
-		legend = Size test
-		10 = PASSWORD
-		10 {
-			label = This field has a size attribute
-			size = 10
-		}
-	}
-
-	# Style
-	110 = FIELDSET
-	110 {
-		legend = Style test
-		10 = PASSWORD
-		10 {
-			label = This field has a style attribute
-			style = border: 1px solid #000000
-		}
-	}
-
-	# Tabindex
-	120 = FIELDSET
-	120 {
-		legend = Tabindex test
-		10 = PASSWORD
-		10 {
-			label = This field has a tabindex attribute
-			tabindex = 1
-		}
-	}
-
-	# Title
-	130 = FIELDSET
-	130 {
-		legend = Title test
-		10 = PASSWORD
-		10 {
-			label = This field has a title attribute
-			title = This is the title text
-		}
-	}
-
-	# Value
-	140 = FIELDSET
-	140 {
-		legend = Value test
-		10 = PASSWORD
-		10 {
-			label = This field has a value attribute
-			value = The value attribute
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/radio.txt b/typo3/sysext/form/Documentation/Tests/Attributes/radio.txt
deleted file mode 100644
index f461cfca212a59fff1f5f4a6f00358be4a69ef79..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/radio.txt
+++ /dev/null
@@ -1,226 +0,0 @@
-form.attributes.radio = FORM
-form.attributes.radio {
-	method = post
-
-	# Label test
-	10 = FIELDSET
-	10 {
-		legend = Label test
-		10 = RADIO
-		10 {
-			label = label
-		}
-		20 = RADIO
-		20 {
-			label.value = label.value
-		}
-		30 = RADIO
-		30 {
-			label = TEXT
-			label {
-				value = TEXT cObj
-			}
-		}
-	}
-
-	# Layout test
-	20 = FIELDSET
-	20 {
-		legend = Layout test
-		10 = RADIO
-		10 {
-			label = label in front of input (default)
-		}
-		20 = RADIO
-		20 {
-			layout (
-				<input />
-				<label />
-			)
-			label = label after input
-		}
-		30 = RADIO
-		30 {
-			layout = <input />
-			value = No label
-		}
-	}
-
-	# Accesskey
-	30 = FIELDSET
-	30 {
-		legend = Accesskey test
-		10 = RADIO
-		10 {
-			label = This radio button has an accesskey
-			accesskey = a
-		}
-	}
-
-	# Alt
-	40 = FIELDSET
-	40 {
-		legend = Alt test
-		10 = RADIO
-		10 {
-			label = This radio button has an alt attribute
-			alt = This is the alt attribute content
-		}
-	}
-
-	# Checked
-	45 = FIELDSET
-	45 {
-		legend = Checked test
-		10 = RADIO
-		10 {
-			label = checked=1
-			checked = 1
-		}
-		20 = RADIO
-		20 {
-			label = checked=0
-			checked = 0
-		}
-		30 = RADIO
-		30 {
-			label = checked=checked
-			checked = checked
-		}
-	}
-
-	# Class
-	50 = FIELDSET
-	50 {
-		legend = Class test
-		10 = RADIO
-		10 {
-			label = This radio button has a class attribute
-			class = classAtribute
-		}
-		20 = RADIO
-		20 {
-			label = Multiple classes
-			class = class1 class2
-		}
-	}
-
-	# Dir
-	60 = FIELDSET
-	60 {
-		legend = Dir test
-		10 = RADIO
-		10 {
-			label = Dir ltr
-			dir = ltr
-		}
-		20 = RADIO
-		20 {
-			label = Dir rtl
-			dir = rtl
-		}
-		30 = RADIO
-		30 {
-			label = Wrong input in dir
-			dir = abc
-		}
-	}
-
-	# Disabled
-	70 = FIELDSET
-	70 {
-		legend = Disabled test
-		10 = RADIO
-		10 {
-			label = disabled=1
-			disabled = 1
-		}
-		20 = RADIO
-		20 {
-			label = disabled=0
-			disabled = 0
-		}
-		30 = RADIO
-		30 {
-			label = disabled=disabled
-			disabled = disabled
-		}
-	}
-
-	# Id
-	80 = FIELDSET
-	80 {
-		legend = Id test
-		10 = RADIO
-		10 {
-			label = This radio button has an id attribute and the label a for attribute
-			id = radioId
-		}
-	}
-
-	# Lang
-	90 = FIELDSET
-	90 {
-		legend = Lang test
-		10 = RADIO
-		10 {
-			label = This radio button has a lang attribute
-			lang = en-US
-		}
-	}
-
-	# Name
-	100 = FIELDSET
-	100 {
-		legend = Name test
-		10 = RADIO
-		10 {
-			label = This radio button has a name attribute
-			name = radioName
-		}
-	}
-
-	# Style
-	110 = FIELDSET
-	110 {
-		legend = style test
-		10 = RADIO
-		10 {
-			label = This radio button has a style attribute
-			style = border: 1px solid #000000
-		}
-	}
-
-	# Tabindex
-	120 = FIELDSET
-	120 {
-		legend = Tabindex test
-		10 = RADIO
-		10 {
-			label = This radio button has a tabindex attribute
-			tabindex = 1
-		}
-	}
-
-	# Title
-	130 = FIELDSET
-	130 {
-		legend = Title test
-		10 = RADIO
-		10 {
-			label = This radio button has a title attribute
-			title = This is the title text
-		}
-	}
-
-	# Value
-	140 = FIELDSET
-	140 {
-		legend = Value test
-		10 = RADIO
-		10 {
-			label = This radio button has a value attribute
-			value = buttonValue
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/radiogroup.txt b/typo3/sysext/form/Documentation/Tests/Attributes/radiogroup.txt
deleted file mode 100644
index eb918cf324a04413de08f7cb1bf1f521abac12df..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/radiogroup.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-form.attributes.radiogroup = FORM
-form.attributes.radiogroup {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = radiogroup
-		}
-	}
-
-	10 = RADIOGROUP
-	10 {
-		legend = Radio Group test
-		name = radiogroup
-
-		10 = RADIO
-		10 {
-			label = Option 1
-		}
-		20 = RADIO
-		20 {
-			label = Option 2
-		}
-		30 = RADIO
-		30 {
-			label = Option 3
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/reset.txt b/typo3/sysext/form/Documentation/Tests/Attributes/reset.txt
deleted file mode 100644
index 29c0fa25e148141a9c77bf1f8763f6717154e737..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/reset.txt
+++ /dev/null
@@ -1,205 +0,0 @@
-form.attributes.reset = FORM
-form.attributes.reset {
-	method = post
-
-	# Label test
-	10 = FIELDSET
-	10 {
-		legend = Label test
-		10 = RESET
-		10 {
-			label = label
-		}
-		20 = RESET
-		20 {
-			label.value = label.value
-		}
-		30 = RESET
-		30 {
-			label = TEXT
-			label {
-				value = TEXT cObj
-			}
-		}
-	}
-
-	# Layout test
-	20 = FIELDSET
-	20 {
-		legend = Layout test
-		10 = RESET
-		10 {
-			label = label in front of input (default)
-		}
-		20 = RESET
-		20 {
-			layout (
-				<input />
-				<label />
-			)
-			label = label after input
-		}
-		30 = RESET
-		30 {
-			layout = <input />
-			value = No label
-		}
-	}
-
-	# Accesskey
-	30 = FIELDSET
-	30 {
-		legend = Accesskey test
-		10 = RESET
-		10 {
-			label = This reset button has an accesskey
-			accesskey = a
-		}
-	}
-
-	# Alt
-	40 = FIELDSET
-	40 {
-		legend = Alt test
-		10 = RESET
-		10 {
-			label = This reset button has an alt attribute
-			alt = This is the alt attribute content
-		}
-	}
-
-	# Class
-	50 = FIELDSET
-	50 {
-		legend = Class test
-		10 = RESET
-		10 {
-			label = This reset button has a class attribute
-			class = classAtribute
-		}
-		20 = RESET
-		20 {
-			label = Multiple classes
-			class = class1 class2
-		}
-	}
-
-	# Dir
-	60 = FIELDSET
-	60 {
-		legend = Dir test
-		10 = RESET
-		10 {
-			label = Dir ltr
-			dir = ltr
-		}
-		20 = RESET
-		20 {
-			label = Dir rtl
-			dir = rtl
-		}
-		30 = RESET
-		30 {
-			label = Wrong input in dir
-			dir = abc
-		}
-	}
-
-	# Disabled
-	70 = FIELDSET
-	70 {
-		legend = Disabled test
-		10 = RESET
-		10 {
-			label = disabled=1
-			disabled = 1
-		}
-		20 = RESET
-		20 {
-			label = disabled=0
-			disabled = 0
-		}
-		30 = RESET
-		30 {
-			label = disabled=disabled
-			disabled = disabled
-		}
-	}
-
-	# Id
-	80 = FIELDSET
-	80 {
-		legend = Id test
-		10 = RESET
-		10 {
-			label = This reset button has an id attribute and the label a for attribute
-			id = resetId
-		}
-	}
-
-	# Lang
-	90 = FIELDSET
-	90 {
-		legend = Lang test
-		10 = RESET
-		10 {
-			label = This reset button has a lang attribute
-			lang = en-US
-		}
-	}
-
-	# Name
-	100 = FIELDSET
-	100 {
-		legend = Name test
-		10 = RESET
-		10 {
-			label = This reset button has a name attribute
-			name = resetName
-		}
-	}
-
-	# Style
-	110 = FIELDSET
-	110 {
-		legend = style test
-		10 = RESET
-		10 {
-			label = This reset button has a style attribute
-			style = border: 1px solid #000000
-		}
-	}
-
-	# Tabindex
-	120 = FIELDSET
-	120 {
-		legend = Tabindex test
-		10 = RESET
-		10 {
-			label = This reset button has a tabindex attribute
-			tabindex = 1
-		}
-	}
-
-	# Title
-	130 = FIELDSET
-	130 {
-		legend = Title test
-		10 = RESET
-		10 {
-			label = This reset button has a title attribute
-			title = This is the title text
-		}
-	}
-
-	# Value
-	140 = FIELDSET
-	140 {
-		legend = Value test
-		10 = RESET
-		10 {
-			label = This reset button has a value attribute
-			value = Don't you dare to push this reset button
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/select.txt b/typo3/sysext/form/Documentation/Tests/Attributes/select.txt
deleted file mode 100644
index 53da9a7d76a269af647838caf8abfd7800bd4bc4..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/select.txt
+++ /dev/null
@@ -1,209 +0,0 @@
-form.tempOption = OPTION
-form.tempOption {
-	data = optionData
-}
-
-form.attributes.select = FORM
-form.attributes.select {
-	method = post
-
-	# Label test
-	10 = FIELDSET
-	10 {
-		legend = Label test
-		10 = SELECT
-		10 {
-			label = label
-			1 < form.tempOption
-		}
-		20 = SELECT
-		20 {
-			label.value = label.value
-			1 < form.tempOption
-		}
-		30 = SELECT
-		30 {
-			label = TEXT
-			label {
-				value = TEXT cObj
-			}
-			1 < form.tempOption
-		}
-	}
-
-	# Layout test
-	20 = FIELDSET
-	20 {
-		legend = Layout test
-		10 = SELECT
-		10 {
-			label = label in front of input (default)
-			1 < form.tempOption
-		}
-		20 = SELECT
-		20 {
-			layout (
-				<select>
-					<elements />
-				</select>
-				<label />
-			)
-			label = label after input
-			1 < form.tempOption
-		}
-		30 = SELECT
-		30 {
-			1 < form.tempOption
-		}
-	}
-
-	# Class
-	30 = FIELDSET
-	30 {
-		legend = Class test
-		10 = SELECT
-		10 {
-			label = This select has a class attribute
-			class = classAtribute
-			1 < form.tempOption
-		}
-		20 = SELECT
-		20 {
-			label = Multiple classes
-			class = class1 class2
-			1 < form.tempOption
-		}
-	}
-
-	# Disabled
-	40 = FIELDSET
-	40 {
-		legend = Disabled test
-		10 = SELECT
-		10 {
-			label = disabled=1
-			disabled = 1
-			1 < form.tempOption
-		}
-		20 = SELECT
-		20 {
-			label = disabled=0
-			disabled = 0
-			1 < form.tempOption
-		}
-		30 = SELECT
-		30 {
-			label = disabled=disabled
-			disabled = disabled
-			1 < form.tempOption
-		}
-	}
-
-	# Id
-	50 = FIELDSET
-	50 {
-		legend = Id test
-		10 = SELECT
-		10 {
-			label = This select has an id attribute and the label a for attribute
-			id = textlineId
-			1 < form.tempOption
-		}
-	}
-
-	# Lang
-	60 = FIELDSET
-	60 {
-		legend = Lang test
-		10 = SELECT
-		10 {
-			label = This select has a lang attribute
-			lang = en-US
-			1 < form.tempOption
-		}
-	}
-
-	# Multiple
-	70 = FIELDSET
-	70 {
-		legend = Multiple test
-		10 = SELECT
-		10 {
-			label = multiple=1
-			multiple = 1
-			1 < form.tempOption
-		}
-		20 = SELECT
-		20 {
-			label = multiple=0
-			multiple = 0
-			1 < form.tempOption
-		}
-		30 = SELECT
-		30 {
-			label = multiple=multiple
-			multiple = multiple
-			1 < form.tempOption
-		}
-	}
-
-	# Name
-	110 = FIELDSET
-	110 {
-		legend = Name test
-		10 = SELECT
-		10 {
-			label = This select has a name attribute
-			name = selectName
-			1 < form.tempOption
-		}
-	}
-
-	# Size
-	120 = FIELDSET
-	120 {
-		legend = Size test
-		10 = SELECT
-		10 {
-			label = This select has a size attribute
-			size = 10
-			1 < form.tempOption
-		}
-	}
-
-	# Style
-	130 = FIELDSET
-	130 {
-		legend = style test
-		10 = SELECT
-		10 {
-			label = This select has a style attribute
-			style = border: 1px solid #000000
-			1 < form.tempOption
-		}
-	}
-
-	# Tabindex
-	140 = FIELDSET
-	140 {
-		legend = Tabindex test
-		10 = SELECT
-		10 {
-			label = This select has a tabindex attribute
-			tabindex = 1
-			1 < form.tempOption
-		}
-	}
-
-	# Title
-	150 = FIELDSET
-	150 {
-		legend = Title test
-		10 = SELECT
-		10 {
-			label = This select has a title attribute
-			title = This is the title text
-			1 < form.tempOption
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/submit.txt b/typo3/sysext/form/Documentation/Tests/Attributes/submit.txt
deleted file mode 100644
index 6abb1e2399b59650e015e0a1ecc3e9ac7a05cabf..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/submit.txt
+++ /dev/null
@@ -1,205 +0,0 @@
-form.attributes.submit = FORM
-form.attributes.submit {
-	method = post
-
-	# Label test
-	10 = FIELDSET
-	10 {
-		legend = Label test
-		10 = SUBMIT
-		10 {
-			label = label
-		}
-		20 = SUBMIT
-		20 {
-			label.value = label.value
-		}
-		30 = SUBMIT
-		30 {
-			label = TEXT
-			label {
-				value = TEXT cObj
-			}
-		}
-	}
-
-	# Layout test
-	20 = FIELDSET
-	20 {
-		legend = Layout test
-		10 = SUBMIT
-		10 {
-			label = label in front of input (default)
-		}
-		20 = SUBMIT
-		20 {
-			layout (
-				<input />
-				<label />
-			)
-			label = label after input
-		}
-		30 = SUBMIT
-		30 {
-			layout = <input />
-			value = No label
-		}
-	}
-
-	# Accesskey
-	30 = FIELDSET
-	30 {
-		legend = Accesskey test
-		10 = SUBMIT
-		10 {
-			label = This submit button has an accesskey
-			accesskey = a
-		}
-	}
-
-	# Alt
-	40 = FIELDSET
-	40 {
-		legend = Alt test
-		10 = SUBMIT
-		10 {
-			label = This submit button has an alt attribute
-			alt = This is the alt attribute content
-		}
-	}
-
-	# Class
-	50 = FIELDSET
-	50 {
-		legend = Class test
-		10 = SUBMIT
-		10 {
-			label = This submit button has a class attribute
-			class = classAtribute
-		}
-		20 = SUBMIT
-		20 {
-			label = Multiple classes
-			class = class1 class2
-		}
-	}
-
-	# Dir
-	60 = FIELDSET
-	60 {
-		legend = Dir test
-		10 = SUBMIT
-		10 {
-			label = Dir ltr
-			dir = ltr
-		}
-		20 = SUBMIT
-		20 {
-			label = Dir rtl
-			dir = rtl
-		}
-		30 = SUBMIT
-		30 {
-			label = Wrong input in dir
-			dir = abc
-		}
-	}
-
-	# Disabled
-	70 = FIELDSET
-	70 {
-		legend = Disabled test
-		10 = SUBMIT
-		10 {
-			label = disabled=1
-			disabled = 1
-		}
-		20 = SUBMIT
-		20 {
-			label = disabled=0
-			disabled = 0
-		}
-		30 = SUBMIT
-		30 {
-			label = disabled=disabled
-			disabled = disabled
-		}
-	}
-
-	# Id
-	80 = FIELDSET
-	80 {
-		legend = Id test
-		10 = SUBMIT
-		10 {
-			label = This submit button has an id attribute and the label a for attribute
-			id = submitId
-		}
-	}
-
-	# Lang
-	90 = FIELDSET
-	90 {
-		legend = Lang test
-		10 = SUBMIT
-		10 {
-			label = This submit button has a lang attribute
-			lang = en-US
-		}
-	}
-
-	# Name
-	100 = FIELDSET
-	100 {
-		legend = Name test
-		10 = SUBMIT
-		10 {
-			label = This submit button has a name attribute
-			name = submitName
-		}
-	}
-
-	# Style
-	110 = FIELDSET
-	110 {
-		legend = style test
-		10 = SUBMIT
-		10 {
-			label = This submit button has a style attribute
-			style = border: 1px solid #000000
-		}
-	}
-
-	# Tabindex
-	120 = FIELDSET
-	120 {
-		legend = Tabindex test
-		10 = SUBMIT
-		10 {
-			label = This submit button has a tabindex attribute
-			tabindex = 1
-		}
-	}
-
-	# Title
-	130 = FIELDSET
-	130 {
-		legend = Title test
-		10 = SUBMIT
-		10 {
-			label = This submit button has a title attribute
-			title = This is the title text
-		}
-	}
-
-	# Value
-	140 = FIELDSET
-	140 {
-		legend = Value test
-		10 = SUBMIT
-		10 {
-			label = This submit button has a value attribute
-			value = Don't you dare to push this reset button
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/textarea.txt b/typo3/sysext/form/Documentation/Tests/Attributes/textarea.txt
deleted file mode 100644
index 92cd34c6388d6a174b8f2d867385f9f92a7846d8..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/textarea.txt
+++ /dev/null
@@ -1,239 +0,0 @@
-form.attributes.textarea = FORM
-form.attributes.textarea {
-	method = post
-
-	# Label test
-	10 = FIELDSET
-	10 {
-		legend = Label test
-		10 = TEXTAREA
-		10 {
-			label = label
-		}
-		20 = TEXTAREA
-		20 {
-			label.value = label.value
-		}
-		30 = TEXTAREA
-		30 {
-			label = TEXT
-			label {
-				value = TEXT cObj
-			}
-		}
-	}
-
-	# Layout test
-	20 = FIELDSET
-	20 {
-		legend = Layout test
-		10 = TEXTAREA
-		10 {
-			label = label in front of input (default)
-		}
-		20 = TEXTAREA
-		20 {
-			layout (
-				<textarea />
-				<label />
-			)
-			label = label after input
-		}
-		30 = TEXTAREA
-		30 {
-			value = No label
-		}
-	}
-
-	# Data test
-	30 = FIELDSET
-	30 {
-		legend = Data test
-		10 = TEXTAREA
-		10 {
-			label = There should be data in the textarea
-			data = There is data in the textarea
-		}
-	}
-
-	# Accesskey
-	40 = FIELDSET
-	40 {
-		legend = Accesskey test
-		10 = TEXTAREA
-		10 {
-			label = This textarea has an accesskey
-			accesskey = a
-		}
-	}
-
-	# Class
-	50 = FIELDSET
-	50 {
-		legend = Class test
-		10 = TEXTAREA
-		10 {
-			label = This textarea has a class attribute
-			class = classAtribute
-		}
-		20 = TEXTAREA
-		20 {
-			label = Multiple classes
-			class = class1 class2
-		}
-	}
-
-	# Cols
-	60 = FIELDSET
-	60 {
-		legend = Cols test
-		10 = TEXTAREA
-		10 {
-			label = This textarea has a cols
-			cols = 100
-		}
-	}
-
-	# Dir
-	70 = FIELDSET
-	70 {
-		legend = Dir test
-		10 = TEXTAREA
-		10 {
-			label = Dir ltr
-			dir = ltr
-		}
-		20 = TEXTAREA
-		20 {
-			label = Dir rtl
-			dir = rtl
-		}
-		30 = TEXTAREA
-		30 {
-			label = Wrong input in dir
-			dir = abc
-		}
-	}
-
-	# Disabled
-	80 = FIELDSET
-	80 {
-		legend = Disabled test
-		10 = TEXTAREA
-		10 {
-			label = disabled=1
-			disabled = 1
-		}
-		20 = TEXTAREA
-		20 {
-			label = disabled=0
-			disabled = 0
-		}
-		30 = TEXTAREA
-		30 {
-			label = disabled=disabled
-			disabled = disabled
-		}
-	}
-
-	# Id
-	90 = FIELDSET
-	90 {
-		legend = Id test
-		10 = TEXTAREA
-		10 {
-			label = This textarea has an id attribute and the label a for attribute
-			id = textareaId
-		}
-	}
-
-	# Lang
-	100 = FIELDSET
-	100 {
-		legend = Lang test
-		10 = TEXTAREA
-		10 {
-			label = This textarea has a lang attribute
-			lang = en-US
-		}
-	}
-
-	# Name
-	110 = FIELDSET
-	110 {
-		legend = Name test
-		10 = TEXTAREA
-		10 {
-			label = This textarea has a name attribute
-			name = textareaName
-		}
-	}
-
-	# Readonly
-	120 = FIELDSET
-	120 {
-		legend = Readonly test
-		10 = TEXTAREA
-		10 {
-			label = readonly=1
-			readonly = 1
-			data = This should be readonly
-		}
-		20 = TEXTAREA
-		20 {
-			label = readonly=0
-			readonly = 0
-			data = This should NOT be readonly
-		}
-		30 = TEXTAREA
-		30 {
-			label = readonly=readonly
-			readonly = readonly
-			data = This should be readonly
-		}
-	}
-
-	# Rows
-	130 = FIELDSET
-	130 {
-		legend = Rows test
-		10 = TEXTAREA
-		10 {
-			label = This textarea has rows
-			rows = 100
-		}
-	}
-
-	# Style
-	140 = FIELDSET
-	140 {
-		legend = style test
-		10 = TEXTAREA
-		10 {
-			label = This textarea has a style attribute
-			style = border: 1px solid #000000
-		}
-	}
-
-	# Tabindex
-	150 = FIELDSET
-	150 {
-		legend = Tabindex test
-		10 = TEXTAREA
-		10 {
-			label = This textarea has a tabindex attribute
-			tabindex = 1
-		}
-	}
-
-	# Title
-	160 = FIELDSET
-	160 {
-		legend = Title test
-		10 = TEXTAREA
-		10 {
-			label = This textarea has a title attribute
-			title = This is the title text
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Attributes/textline.txt b/typo3/sysext/form/Documentation/Tests/Attributes/textline.txt
deleted file mode 100644
index 4d7251be836a92c8b9c25ec06023dfed86f50004..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Attributes/textline.txt
+++ /dev/null
@@ -1,250 +0,0 @@
-form.attributes.textline = FORM
-form.attributes.textline {
-	method = post
-
-	# Label test
-	10 = FIELDSET
-	10 {
-		legend = Label test
-		10 = TEXTLINE
-		10 {
-			label = label
-		}
-		20 = TEXTLINE
-		20 {
-			label.value = label.value
-		}
-		30 = TEXTLINE
-		30 {
-			label = TEXT
-			label {
-				value = TEXT cObj
-			}
-		}
-	}
-
-	# Layout test
-	20 = FIELDSET
-	20 {
-		legend = Layout test
-		10 = TEXTLINE
-		10 {
-			label = label in front of input (default)
-		}
-		20 = TEXTLINE
-		20 {
-			layout (
-				<input />
-				<label />
-			)
-			label = label after input
-		}
-		30 = TEXTLINE
-		30 {
-			value = No label
-		}
-	}
-
-	# Accesskey
-	30 = FIELDSET
-	30 {
-		legend = Accesskey test
-		10 = TEXTLINE
-		10 {
-			label = This textline has an accesskey
-			accesskey = a
-		}
-	}
-
-	# Alt
-	40 = FIELDSET
-	40 {
-		legend = Alt test
-		10 = TEXTLINE
-		10 {
-			label = This submit button has an alt attribute
-			alt = This is the alt attribute content
-		}
-	}
-
-	# Class
-	50 = FIELDSET
-	50 {
-		legend = Class test
-		10 = TEXTLINE
-		10 {
-			label = This textline has a class attribute
-			class = classAtribute
-		}
-		20 = TEXTLINE
-		20 {
-			label = Multiple classes
-			class = class1 class2
-		}
-	}
-
-	# Dir
-	60 = FIELDSET
-	60 {
-		legend = Dir test
-		10 = TEXTLINE
-		10 {
-			label = Dir ltr
-			dir = ltr
-		}
-		20 = TEXTLINE
-		20 {
-			label = Dir rtl
-			dir = rtl
-		}
-		30 = TEXTLINE
-		30 {
-			label = Wrong input in dir
-			dir = abc
-		}
-	}
-
-	# Disabled
-	70 = FIELDSET
-	70 {
-		legend = Disabled test
-		10 = TEXTLINE
-		10 {
-			label = disabled=1
-			disabled = 1
-		}
-		20 = TEXTLINE
-		20 {
-			label = disabled=0
-			disabled = 0
-		}
-		30 = TEXTLINE
-		30 {
-			label = disabled=disabled
-			disabled = disabled
-		}
-	}
-
-	# Id
-	80 = FIELDSET
-	80 {
-		legend = Id test
-		10 = TEXTLINE
-		10 {
-			label = This textline has an id attribute and the label a for attribute
-			id = textlineId
-		}
-	}
-
-	# Lang
-	90 = FIELDSET
-	90 {
-		legend = Lang test
-		10 = TEXTLINE
-		10 {
-			label = This textline has a lang attribute
-			lang = en-US
-		}
-	}
-
-	# Maxlength
-	100 = FIELDSET
-	100 {
-		legend = Maxlength test
-		10 = TEXTLINE
-		10 {
-			label = This textline has a maxlength attribute
-			maxlength = 10
-		}
-	}
-
-	# Name
-	110 = FIELDSET
-	110 {
-		legend = Name test
-		10 = TEXTLINE
-		10 {
-			label = This textline has a name attribute
-			name = textlineName
-		}
-	}
-
-	# Readonly
-	120 = FIELDSET
-	120 {
-		legend = Readonly test
-		10 = TEXTLINE
-		10 {
-			label = readonly=1
-			readonly = 1
-			data = This should be readonly
-		}
-		20 = TEXTLINE
-		20 {
-			label = readonly=0
-			readonly = 0
-			data = This should NOT be readonly
-		}
-		30 = TEXTLINE
-		30 {
-			label = readonly=readonly
-			readonly = readonly
-			data = This should be readonly
-		}
-	}
-
-	# Size
-	130 = FIELDSET
-	130 {
-		legend = Size test
-		10 = TEXTLINE
-		10 {
-			label = This textline has a size attribute
-			size = 10
-		}
-	}
-
-	# Style
-	140 = FIELDSET
-	140 {
-		legend = style test
-		10 = TEXTLINE
-		10 {
-			label = This textline has a style attribute
-			style = border: 1px solid #000000
-		}
-	}
-
-	# Tabindex
-	150 = FIELDSET
-	150 {
-		legend = Tabindex test
-		10 = TEXTLINE
-		10 {
-			label = This textline has a tabindex attribute
-			tabindex = 1
-		}
-	}
-
-	# Title
-	160 = FIELDSET
-	160 {
-		legend = Title test
-		10 = TEXTLINE
-		10 {
-			label = This textline has a title attribute
-			title = This is the title text
-		}
-	}
-
-	# Value
-	170 = FIELDSET
-	170 {
-		legend = Value test
-		10 = TEXTLINE
-		10 {
-			label = This textline has a value attribute
-			value = The value attribute
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Filter/alphabetic.txt b/typo3/sysext/form/Documentation/Tests/Filter/alphabetic.txt
deleted file mode 100644
index 9df926f7080c3b1e07500f320cfda1512b1dae67..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Filter/alphabetic.txt
+++ /dev/null
@@ -1,56 +0,0 @@
-form.filter.alphabetic = FORM
-form.filter.alphabetic {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = textlineField
-		}
-	}
-
-	# Alphabetic
-	10 = FIELDSET
-	10 {
-		legend = Alphabetic test
-		10 = TEXTLINE
-		10 {
-			label = no settings
-			value = John Doe 3
-			filters {
-				1 = alphabetic
-			}
-		}
-		20 = TEXTLINE
-		20 {
-			label = allowWhiteSpace=1
-			value = John Doe 3
-			filters {
-				1 = alphabetic
-				1 {
-					allowWhiteSpace = 1
-				}
-			}
-		}
-	}
-
-	# A textline which must be empty to test the above
-	30 = FIELDSET
-	30 {
-		legend = Leave empty to get the form back after submitting
-		10 = TEXTLINE
-		10 {
-			name = textlineField
-			label = Leave me empty
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Filter/alphanumeric.txt b/typo3/sysext/form/Documentation/Tests/Filter/alphanumeric.txt
deleted file mode 100644
index f6c965c704290e3172fc63b7fd91536a5bfcd3df..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Filter/alphanumeric.txt
+++ /dev/null
@@ -1,56 +0,0 @@
-form.filter.alphanumeric = FORM
-form.filter.alphanumeric {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = textlineField
-		}
-	}
-
-	# Alphanumeric
-	10 = FIELDSET
-	10 {
-		legend = Alphanumeric test
-		10 = TEXTLINE
-		10 {
-			label = no settings
-			value = John Doe 3 #$
-			filters {
-				1 = alphanumeric
-			}
-		}
-		20 = TEXTLINE
-		20 {
-			label = allowWhiteSpace=1
-			value = John Doe 3 #$
-			filters {
-				1 = alphanumeric
-				1 {
-					allowWhiteSpace = 1
-				}
-			}
-		}
-	}
-
-	# A textline which must be empty to test the above
-	30 = FIELDSET
-	30 {
-		legend = Leave empty to get the form back after submitting
-		10 = TEXTLINE
-		10 {
-			name = textlineField
-			label = Leave me empty
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Filter/currency.txt b/typo3/sysext/form/Documentation/Tests/Filter/currency.txt
deleted file mode 100644
index dc5aeb2e331b45b26398fc25b0e978e714638a72..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Filter/currency.txt
+++ /dev/null
@@ -1,68 +0,0 @@
-form.filter.currency = FORM
-form.filter.currency {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = textlineField
-		}
-	}
-
-	# Currency
-	10 = FIELDSET
-	10 {
-		legend = Currency test
-		10 = TEXTLINE
-		10 {
-			label = no settings
-			value = John Doe 3 #$
-			filters {
-				1 = currency
-			}
-		}
-		20 = TEXTLINE
-		20 {
-			label = decimalPoint=,
-			value = John Doe 3 #$
-			filters {
-				1 = currency
-				1 {
-					decimalPoint = ,
-				}
-			}
-		}
-		30 = TEXTLINE
-		30 {
-			label = decimalPoint=, / thousandSeparator=space
-			value = John Doe 3 #$
-			filters {
-				1 = currency
-				1 {
-					decimalPoint = ,
-					thousandSeparator = space
-				}
-			}
-		}
-	}
-
-	# A textline which must be empty to test the above
-	30 = FIELDSET
-	30 {
-		legend = Leave empty to get the form back after submitting
-		10 = TEXTLINE
-		10 {
-			name = textlineField
-			label = Leave me empty
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Filter/digit.txt b/typo3/sysext/form/Documentation/Tests/Filter/digit.txt
deleted file mode 100644
index d6fc155be035922da89af0af75fc682239efea21..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Filter/digit.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-form.filter.digit = FORM
-form.filter.digit {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = textlineField
-		}
-	}
-
-	# Digit
-	10 = FIELDSET
-	10 {
-		legend = Digit test
-		10 = TEXTLINE
-		10 {
-			label = no settings
-			value = John Doe 3 #$
-			filters {
-				1 = digit
-			}
-		}
-	}
-
-	# A textline which must be empty to test the above
-	30 = FIELDSET
-	30 {
-		legend = Leave empty to get the form back after submitting
-		10 = TEXTLINE
-		10 {
-			name = textlineField
-			label = Leave me empty
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Filter/integer.txt b/typo3/sysext/form/Documentation/Tests/Filter/integer.txt
deleted file mode 100644
index e6cc33b24039f0293640286b896b4cbf97a771b3..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Filter/integer.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-form.filter.integer = FORM
-form.filter.integer {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = textlineField
-		}
-	}
-
-	# Integer
-	10 = FIELDSET
-	10 {
-		legend = Integer test
-		10 = TEXTLINE
-		10 {
-			label = no settings
-			value = John Doe 3 #$
-			filters {
-				1 = integer
-			}
-		}
-	}
-
-	# A textline which must be empty to test the above
-	30 = FIELDSET
-	30 {
-		legend = Leave empty to get the form back after submitting
-		10 = TEXTLINE
-		10 {
-			name = textlineField
-			label = Leave me empty
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Filter/lowercase.txt b/typo3/sysext/form/Documentation/Tests/Filter/lowercase.txt
deleted file mode 100644
index 536013a499f1148d23487e0e80bf79d85ddbad26..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Filter/lowercase.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-form.filter.lowercase = FORM
-form.filter.lowercase {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = textlineField
-		}
-	}
-
-	# Lower case
-	10 = FIELDSET
-	10 {
-		legend = Lower case test
-		10 = TEXTLINE
-		10 {
-			label = no settings
-			value = John Doe 3 #$
-			filters {
-				1 = lowercase
-			}
-		}
-	}
-
-	# A textline which must be empty to test the above
-	30 = FIELDSET
-	30 {
-		legend = Leave empty to get the form back after submitting
-		10 = TEXTLINE
-		10 {
-			name = textlineField
-			label = Leave me empty
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Filter/regexp.txt b/typo3/sysext/form/Documentation/Tests/Filter/regexp.txt
deleted file mode 100644
index 04cf247fe6a4c211f83e4a7104656921d45460fb..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Filter/regexp.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-form.filter.regexp = FORM
-form.filter.regexp {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = textlineField
-		}
-	}
-
-	# Regular expression
-	10 = FIELDSET
-	10 {
-		legend = Regular expression test
-		10 = TEXTLINE
-		10 {
-			label = using regexp /[^a-zA-Z]/u
-			value = John Doe 3 #$
-			filters {
-				1 = regexp
-				1 {
-					expression = /[^a-zA-Z]/u
-				}
-			}
-		}
-	}
-
-	# A textline which must be empty to test the above
-	30 = FIELDSET
-	30 {
-		legend = Leave empty to get the form back after submitting
-		10 = TEXTLINE
-		10 {
-			name = textlineField
-			label = Leave me empty
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Filter/stripnewlines.txt b/typo3/sysext/form/Documentation/Tests/Filter/stripnewlines.txt
deleted file mode 100644
index ebc546270a3a4505444c8193059d0a44438e9d51..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Filter/stripnewlines.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-form.filter.stripnewlines = FORM
-form.filter.stripnewlines {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = textlineField
-		}
-	}
-
-	# Strip newlines
-	10 = FIELDSET
-	10 {
-		legend = Strip newlines test
-		10 = TEXTAREA
-		10 {
-			label = No settings
-			data (
-line 1
-line 2
-line 3
-			)
-			filters {
-				1 = stripnewlines
-			}
-		}
-	}
-
-	# A textline which must be empty to test the above
-	30 = FIELDSET
-	30 {
-		legend = Leave empty to get the form back after submitting
-		10 = TEXTLINE
-		10 {
-			name = textlineField
-			label = Leave me empty
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Filter/titlecase.txt b/typo3/sysext/form/Documentation/Tests/Filter/titlecase.txt
deleted file mode 100644
index cfa4e5840dc52db9a59b51d79979ae747149e396..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Filter/titlecase.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-form.filter.titlecase = FORM
-form.filter.titlecase {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = textlineField
-		}
-	}
-
-	# Title case
-	10 = FIELDSET
-	10 {
-		legend = Title case test
-		10 = TEXTLINE
-		10 {
-			label = No settings
-			value = kasper skårhøj
-			filters {
-				1 = titlecase
-			}
-		}
-	}
-
-	# A textline which must be empty to test the above
-	30 = FIELDSET
-	30 {
-		legend = Leave empty to get the form back after submitting
-		10 = TEXTLINE
-		10 {
-			name = textlineField
-			label = Leave me empty
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Filter/trim.txt b/typo3/sysext/form/Documentation/Tests/Filter/trim.txt
deleted file mode 100644
index 60d87d762f898417b45b2764f3ec4f119bfac256..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Filter/trim.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-form.filter.trim = FORM
-form.filter.trim {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = textlineField
-		}
-	}
-
-	# Trim
-	10 = FIELDSET
-	10 {
-		legend = Trim test
-		10 = TEXTAREA
-		10 {
-			label = No settings
-			data (
-				line 1
-				line 2
-				line 3
-			)
-			filters {
-				1 = trim
-			}
-		}
-		20 = TEXTLINE
-		20 {
-			label = characterList=a,b,f,g
-			value = abcdefg
-			filters {
-				1 = trim
-				1 {
-					characterList = a,b,f,g
-				}
-			}
-		}
-	}
-
-	# A textline which must be empty to test the above
-	30 = FIELDSET
-	30 {
-		legend = Leave empty to get the form back after submitting
-		10 = TEXTLINE
-		10 {
-			name = textlineField
-			label = Leave me empty
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Filter/uppercase.txt b/typo3/sysext/form/Documentation/Tests/Filter/uppercase.txt
deleted file mode 100644
index b064a86e422325f9ac5df716fb0394f321c059f5..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Filter/uppercase.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-form.filter.uppercase = FORM
-form.filter.uppercase {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = textlineField
-		}
-	}
-
-	# Upper case
-	10 = FIELDSET
-	10 {
-		legend = Upper case test
-		10 = TEXTLINE
-		10 {
-			label = no settings
-			value = John Doe 3 #$
-			filters {
-				1 = uppercase
-			}
-		}
-	}
-
-	# A textline which must be empty to test the above
-	30 = FIELDSET
-	30 {
-		legend = Leave empty to get the form back after submitting
-		10 = TEXTLINE
-		10 {
-			name = textlineField
-			label = Leave me empty
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Request/checkbox.txt b/typo3/sysext/form/Documentation/Tests/Request/checkbox.txt
deleted file mode 100644
index e938f9cbd57738a173a4fdc68809f37f66100210..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Request/checkbox.txt
+++ /dev/null
@@ -1,70 +0,0 @@
-form.request.checkbox = FORM
-form.request.checkbox {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = textlineField
-		}
-	}
-
-	# Checked test
-	10 = FIELDSET
-	10 {
-		legend = Checked test
-		10 = CHECKBOX
-		10 {
-			label = Uncheck me
-			checked = checked
-		}
-		20 = CHECKBOX
-		20 {
-			label = Check me
-		}
-	}
-
-	# Multiple test
-	20 = FIELDSET
-	20 {
-		legend = Multiple test
-		10 = CHECKBOX
-		10 {
-			label = Check 1
-			name = checkmultiple
-			value = check1
-		}
-		20 = CHECKBOX
-		20 {
-			label = Check 2
-			name = checkmultiple
-			value = check2
-		}
-		30 = CHECKBOX
-		30 {
-			label = Check 3
-			name = checkmultiple
-			value = check3
-		}
-	}
-
-	# A textline which must be empty to test the above
-	30 = FIELDSET
-	30 {
-		legend = Leave empty to get the form back after submitting
-		10 = TEXTLINE
-		10 {
-			name = textlineField
-			label = Leave me empty
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Request/option.txt b/typo3/sysext/form/Documentation/Tests/Request/option.txt
deleted file mode 100644
index c02c6a440656660246cea6eac43de869d6efacb0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Request/option.txt
+++ /dev/null
@@ -1,127 +0,0 @@
-form.request.option = FORM
-form.request.option {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = textlineField
-		}
-	}
-
-	# Selected test
-	10 = FIELDSET
-	10 {
-		legend = Selected test
-		10 = SELECT
-		10 {
-			1 = OPTION
-			1 {
-				data = Select me
-				value = option2
-			}
-			2 = OPTION
-			2 {
-				data = Deselect me
-				selected = selected
-				value = option1
-			}
-		}
-	}
-
-	# Regular test
-	20 = FIELDSET
-	20 {
-		legend = Regular test
-		10 = SELECT
-		10 {
-			1 = OPTION
-			1 {
-				data = Option 1
-				value = option1
-			}
-			2 = OPTION
-			2 {
-				data = Option 2
-				value = option2
-			}
-			3 = OPTION
-			3 {
-				data = Option 3
-				value = option3
-			}
-		}
-	}
-
-	# Multiple test
-	30 = FIELDSET
-	30 {
-		legend = Regular test
-		10 = SELECT
-		10 {
-			multiple = multiple
-			1 = OPTION
-			1 {
-				data = Option 1
-				value = option1
-			}
-			2 = OPTION
-			2 {
-				data = Option 2
-				value = option2
-			}
-			3 = OPTION
-			3 {
-				data = Option 3
-				value = option3
-			}
-		}
-	}
-
-	# Multiple selected test
-	40 = FIELDSET
-	40 {
-		legend = Regular test
-		10 = SELECT
-		10 {
-			multiple = multiple
-			1 = OPTION
-			1 {
-				data = Uncheck me 1
-				value = option1
-				selected = selected
-			}
-			2 = OPTION
-			2 {
-				data = Check me
-				value = option2
-			}
-			3 = OPTION
-			3 {
-				data = Uncheck me 2
-				value = option3
-				selected = selected
-			}
-		}
-	}
-
-	# A textline which must be empty to test the above
-	50 = FIELDSET
-	50 {
-		legend = Leave empty to get the form back after submitting
-		10 = TEXTLINE
-		10 {
-			name = textlineField
-			label = Leave me empty
-		}
-	}
-
-	# Submit
-	60 = FIELDSET
-	60 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Request/radio.txt b/typo3/sysext/form/Documentation/Tests/Request/radio.txt
deleted file mode 100644
index 0cb778fdd47c4eac48eee3bb9d2f1e08a0a297a5..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Request/radio.txt
+++ /dev/null
@@ -1,74 +0,0 @@
-form.request.radio = FORM
-form.request.radio {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = textlineField
-		}
-	}
-
-	# Checked test
-	10 = FIELDSET
-	10 {
-		legend = Checked test
-		10 = RADIO
-		10 {
-			label = Uncheck me
-			checked = checked
-			name = checkmultiple
-			value = check1
-		}
-		20 = RADIO
-		20 {
-			label = Check me
-			name = checkmultiple
-			value = check2
-		}
-	}
-
-	# Radio group
-	20 = FIELDSET
-	20 {
-		legend = Radio group
-		10 = RADIO
-		10 {
-			label = Check 1
-			name = checkmultiple2
-			value = check1
-		}
-		20 = RADIO
-		20 {
-			label = Check 2
-			name = checkmultiple2
-			value = check2
-		}
-		30 = RADIO
-		30 {
-			label = Check 3
-			name = checkmultiple2
-			value = check3
-		}
-	}
-
-	# A textline which must be empty to test the above
-	30 = FIELDSET
-	30 {
-		legend = Leave empty to get the form back after submitting
-		10 = TEXTLINE
-		10 {
-			name = textlineField
-			label = Leave me empty
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/alphabetic.txt b/typo3/sysext/form/Documentation/Tests/Validation/alphabetic.txt
deleted file mode 100644
index bfdb5ec6289b66fb9ba9dad64a189cba247f943a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/alphabetic.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-form.validation.alphabetic = FORM
-form.validation.alphabetic {
-	method = post
-
-	rules {
-		1 = alphabetic
-		1 {
-			element = alphabetic1
-		}
-		2 = alphabetic
-		2 {
-			element = alphabetic2
-			allowWhiteSpace = 1
-		}
-	}
-
-	# Alphabetic
-	10 = FIELDSET
-	10 {
-		legend = Alphabetic test
-		10 = TEXTLINE
-		10 {
-			label = no settings
-			value = 12345
-			name = alphabetic1
-		}
-		20 = TEXTLINE
-		20 {
-			label = allowWhiteSpace=1
-			value = 12345
-			name = alphabetic2
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/alphanumeric.txt b/typo3/sysext/form/Documentation/Tests/Validation/alphanumeric.txt
deleted file mode 100644
index d25e82610fe87c43396fcea0f42e68ef8f00ae28..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/alphanumeric.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-form.validation.alphanumeric = FORM
-form.validation.alphanumeric {
-	method = post
-
-	rules {
-		1 = alphanumeric
-		1 {
-			element = alphanumeric1
-		}
-		2 = alphanumeric
-		2 {
-			element = alphanumeric2
-			allowWhiteSpace = 1
-		}
-	}
-
-	# Alpahnumeric
-	10 = FIELDSET
-	10 {
-		legend = Alphanumeric test
-		10 = TEXTLINE
-		10 {
-			label = no settings
-			value = !@#$%^
-			name = alphanumeric1
-		}
-		20 = TEXTLINE
-		20 {
-			label = allowWhiteSpace=1
-			value = !@#$%^
-			name = alphanumeric2
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/between.txt b/typo3/sysext/form/Documentation/Tests/Validation/between.txt
deleted file mode 100644
index 3a324084d9146e435c69907148d7d4e5ef007072..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/between.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-form.validation.between = FORM
-form.validation.between {
-	method = post
-
-	rules {
-		1 = between
-		1 {
-			element = between1
-			minimum = 5
-			maximum = 10
-		}
-		2 = between
-		2 {
-			element = between2
-			minimum = 5
-			maximum = 10
-			inclusive = 1
-		}
-	}
-
-	# Between
-	10 = FIELDSET
-	10 {
-		legend = Between test
-		10 = TEXTLINE
-		10 {
-			label = Between 5 and 10
-			value = abcdef
-			name = between1
-		}
-		20 = TEXTLINE
-		20 {
-			label = Between 5 and 10, inclusive
-			value = abcdef
-			name = between2
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/combined.txt b/typo3/sysext/form/Documentation/Tests/Validation/combined.txt
deleted file mode 100644
index 54095e04e2030d435bca85dee5b6ffef146bcec5..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/combined.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-form.validation.combined = FORM
-form.validation.combined {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = email1
-		}
-		2 = email
-		2 {
-			element = email1
-		}
-	}
-
-	# Email
-	10 = FIELDSET
-	10 {
-		legend = Email test
-		10 = TEXTLINE
-		10 {
-			label = Email address
-			value = abc!@#
-			name = email1
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/date.txt b/typo3/sysext/form/Documentation/Tests/Validation/date.txt
deleted file mode 100644
index e8612654ced2c4a059daeee7ad38248dad51bee4..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/date.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-form.validation.date = FORM
-form.validation.date {
-	method = post
-
-	rules {
-		1 = date
-		1 {
-			element = date1
-		}
-	}
-
-	# Date
-	10 = FIELDSET
-	10 {
-		legend = Date test
-		10 = TEXTLINE
-		10 {
-			label = Date %e-%m-%Y
-			value = 34-13-01
-			name = date1
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/digit.txt b/typo3/sysext/form/Documentation/Tests/Validation/digit.txt
deleted file mode 100644
index 45dd766f1774da8939f676c64d5d9185c2747819..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/digit.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-form.validation.digit = FORM
-form.validation.digit {
-	method = post
-
-	rules {
-		1 = digit
-		1 {
-			element = digit1
-		}
-	}
-
-	# Digit
-	10 = FIELDSET
-	10 {
-		legend = Digit test
-		10 = TEXTLINE
-		10 {
-			label = Digit
-			value = abc!@#
-			name = digit1
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/email.txt b/typo3/sysext/form/Documentation/Tests/Validation/email.txt
deleted file mode 100644
index bd6f487fd30329c6b15b223d7db5e51a00bb213f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/email.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-form.validation.email = FORM
-form.validation.email {
-	method = post
-
-	rules {
-		1 = email
-		1 {
-			element = email1
-		}
-	}
-
-	# Email
-	10 = FIELDSET
-	10 {
-		legend = Email test
-		10 = TEXTLINE
-		10 {
-			label = Email address
-			value = abc!@#
-			name = email1
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/equals.txt b/typo3/sysext/form/Documentation/Tests/Validation/equals.txt
deleted file mode 100644
index 12e0968ca942c474e70f82ea8e5f5feacf8aa3aa..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/equals.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-form.validation.equals = FORM
-form.validation.equals {
-	method = post
-
-	rules {
-		1 = equals
-		1 {
-			element = equals1
-			field = equals2
-		}
-	}
-
-	# Equals
-	10 = FIELDSET
-	10 {
-		legend = Equals test
-		10 = TEXTLINE
-		10 {
-			label = First field
-			value = abcde
-			name = equals1
-		}
-		20 = TEXTLINE
-		20 {
-			label = Second field
-			value = abcdef
-			name = equals2
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/float.txt b/typo3/sysext/form/Documentation/Tests/Validation/float.txt
deleted file mode 100644
index e82c3f6b168a9614bf464ae4475d33da47a3c9ae..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/float.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-form.validation.float = FORM
-form.validation.float {
-	method = post
-
-	rules {
-		1 = float
-		1 {
-			element = float1
-		}
-	}
-
-	# Float
-	10 = FIELDSET
-	10 {
-		legend = Float test
-		10 = TEXTLINE
-		10 {
-			label = Float
-			value = abcde
-			name = float1
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/greaterthan.txt b/typo3/sysext/form/Documentation/Tests/Validation/greaterthan.txt
deleted file mode 100644
index 01385a0dc060717d6ccd1e544043e4ddef3f10dc..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/greaterthan.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-form.validation.greaterthan = FORM
-form.validation.greaterthan {
-	method = post
-
-	rules {
-		1 = greaterthan
-		1 {
-			element = greaterthan1
-			minimum = 5
-		}
-	}
-
-	# Greater than
-	10 = FIELDSET
-	10 {
-		legend = Greater than test
-		10 = TEXTLINE
-		10 {
-			label = Greater than
-			value = abcde
-			name = greaterthan1
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/inarray.txt b/typo3/sysext/form/Documentation/Tests/Validation/inarray.txt
deleted file mode 100644
index b21add2530de9c94940698845aa6519035564e85..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/inarray.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-form.validation.inarray = FORM
-form.validation.inarray {
-	method = post
-
-	rules {
-		1 = inarray
-		1 {
-			element = inarray1
-			array {
-				1 = TYPO3
-				2 = FLOW3
-				3 = CMS
-				4 = OPEN SOURCE
-			}
-		}
-	}
-
-	# In Array
-	10 = FIELDSET
-	10 {
-		legend = In array test
-		10 = TEXTLINE
-		10 {
-			label = Type TYPO3, FLOW3, CMS or OPEN SOURCE here
-			value = abcde
-			name = inarray1
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/integer.txt b/typo3/sysext/form/Documentation/Tests/Validation/integer.txt
deleted file mode 100644
index edb52352c3a116266ff80ff0f2c3a53e6a27adb0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/integer.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-form.validation.integer = FORM
-form.validation.integer {
-	method = post
-
-	rules {
-		1 = integer
-		1 {
-			element = integer1
-		}
-	}
-
-	# Integer
-	10 = FIELDSET
-	10 {
-		legend = Integer test
-		10 = TEXTLINE
-		10 {
-			label = Type an integer
-			value = abcde
-			name = integer1
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/ip.txt b/typo3/sysext/form/Documentation/Tests/Validation/ip.txt
deleted file mode 100644
index d8005a3fad4ac2aa73bdf956f17e980dc0d0435d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/ip.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-form.validation.ip = FORM
-form.validation.ip {
-	method = post
-
-	rules {
-		1 = ip
-		1 {
-			element = ip1
-		}
-	}
-
-	# IP
-	10 = FIELDSET
-	10 {
-		legend = IP test
-		10 = TEXTLINE
-		10 {
-			label = Type an IP
-			value = abcde
-			name = ip1
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/length.txt b/typo3/sysext/form/Documentation/Tests/Validation/length.txt
deleted file mode 100644
index fd9cdcdb5e525404ddf065af452b7d8f6e95fc55..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/length.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-form.validation.length = FORM
-form.validation.length {
-	method = post
-
-	rules {
-		1 = length
-		1 {
-			element = length1
-			minimum = 6
-		}
-		2 = length
-		2 {
-			element = length2
-			minimum = 2
-			maximum = 4
-		}
-	}
-
-	# Length
-	10 = FIELDSET
-	10 {
-		legend = Length test
-		10 = TEXTLINE
-		10 {
-			label = Only minimum
-			value = abcde
-			name = length1
-		}
-		20 = TEXTLINE
-		20 {
-			label = Minimum and maximum
-			value = abcde
-			name = length2
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/lessthan.txt b/typo3/sysext/form/Documentation/Tests/Validation/lessthan.txt
deleted file mode 100644
index e2a80edea896a7296c571c6939f3994c8279b58f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/lessthan.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-form.validation.lessthan = FORM
-form.validation.lessthan {
-	method = post
-
-	rules {
-		1 = lessthan
-		1 {
-			element = lessthan1
-			maximum = 10
-		}
-	}
-
-	# Less than
-	10 = FIELDSET
-	10 {
-		legend = Less than test
-		10 = TEXTLINE
-		10 {
-			label = Less than
-			value = abcde
-			name = lessthan1
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/regexp.txt b/typo3/sysext/form/Documentation/Tests/Validation/regexp.txt
deleted file mode 100644
index 21cf11f9d8e5dbae8035b7196d1d4524b1635d6f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/regexp.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-form.validation.regexp = FORM
-form.validation.regexp {
-	method = post
-
-	rules {
-		1 = regexp
-		1 {
-			element = regexp1
-			expression = /\b(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d|2[0-4]\d|25[0-5])\b/
-		}
-	}
-
-	# Regexp
-	10 = FIELDSET
-	10 {
-		legend = Regexp test
-		10 = TEXTLINE
-		10 {
-			label = IP number
-			value = abcde
-			name = regexp1
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/required.txt b/typo3/sysext/form/Documentation/Tests/Validation/required.txt
deleted file mode 100644
index 8c01e733a989e36f61bcfa1c5e33398ec794636c..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/required.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-form.validation.required = FORM
-form.validation.required {
-	method = post
-
-	rules {
-		1 = required
-		1 {
-			element = required1
-		}
-	}
-
-	# Required
-	10 = FIELDSET
-	10 {
-		legend = Required test
-		10 = TEXTLINE
-		10 {
-			label = Leave empty to trigger error
-			name = required1
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Documentation/Tests/Validation/uri.txt b/typo3/sysext/form/Documentation/Tests/Validation/uri.txt
deleted file mode 100644
index 386c975451e084deeebbd48d7fd348a19c67beba..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Documentation/Tests/Validation/uri.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-form.validation.uri = FORM
-form.validation.uri {
-	method = post
-
-	rules {
-		1 = uri
-		1 {
-			element = uri1
-		}
-	}
-
-	# URI
-	10 = FIELDSET
-	10 {
-		legend = URI test
-		10 = TEXTLINE
-		10 {
-			label = URI
-			value = abcde
-			name = uri1
-		}
-	}
-
-	# Submit
-	40 = FIELDSET
-	40 {
-		10 = SUBMIT
-		10 {
-			value = Submit
-		}
-	}
-}
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Layouts/FormEditor.html b/typo3/sysext/form/Resources/Private/Backend/Layouts/FormEditor.html
new file mode 100644
index 0000000000000000000000000000000000000000..9fcdc2812e8e30a8a5153d3640fae16841865312
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Layouts/FormEditor.html
@@ -0,0 +1,54 @@
+{namespace core = TYPO3\CMS\Core\ViewHelpers}
+{namespace formvh = TYPO3\CMS\Form\ViewHelpers}
+
+<formvh:be.pageRenderer
+    loadExtJsTheme="false"
+    loadJQuery="true"
+    includeCssFiles="{stylesheets}"
+    addInlineSettings="{addInlineSettings}"
+    includeJsFiles="{0: 'EXT:backend/Resources/Public/JavaScript/jsfunc.tbe_editor.js'}"
+/>
+
+<div data-identifier="moduleLoadingIndicator" class="form-editor-loading-spinner">
+    <core:icon identifier="spinner-circle-dark" size="default" />
+    <div class="form-editor-loading-spinner-label"><f:translate key="LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.loading" /></div>
+</div>
+
+<div data-identifier="moduleWrapper" class="hidden">
+    <f:for each="{formEditorTemplates}" key="formEditorTemplateName" as="formEditorTemplate">
+        <script type="text/x-formeditor-template" data-template-name="{formEditorTemplateName}">
+            <f:format.raw>{formEditorTemplate}</f:format.raw>
+        </script>
+    </f:for>
+
+    <section id="t3-form-navigation-component" class="t3-form-x-component" data-identifier="structureSection">
+        <div id="t3-form-structure-panel">
+            <f:render section="ElementSidebarTree"/>
+        </div>
+    </section>
+
+    <section id="t3-form-stage-container" data-identifier="stageContainer">
+        <div id="t3-form-stage-inner-container">
+            <header id="t3-form-stage-header">
+                <f:render section="Header"/>
+            </header>
+            <div id="t3-form-stage-content">
+                <f:render section="Stage"/>
+            </div>
+        </div>
+    </section>
+
+    <section id="t3-form-inspector-panels-container" class="t3-form-x-component" data-identifier="inspectorSection">
+        <f:render section="Inspector"/>
+    </section>
+</div>
+
+<script type="text/javascript">
+    require(['{dynamicRequireJsModules.app}', '{dynamicRequireJsModules.mediator}', '{dynamicRequireJsModules.viewModel}'], function (formEditorApp, mediator, viewModel) {
+        window.TYPO3.FORMEDITOR_APP = formEditorApp.getInstance(
+            <f:format.htmlentitiesDecode>{formEditorAppInitialData}</f:format.htmlentitiesDecode>,
+            mediator,
+            viewModel
+        ).run();
+    });
+</script>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Layouts/FormManager.html b/typo3/sysext/form/Resources/Private/Backend/Layouts/FormManager.html
new file mode 100644
index 0000000000000000000000000000000000000000..3d0054fb9b68b43bfee354796df0a8222a6aef6a
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Layouts/FormManager.html
@@ -0,0 +1,7 @@
+<f:be.pageRenderer
+    loadExtJsTheme="false"
+    includeCssFiles="{stylesheets}"
+/>
+
+<f:flashMessages class="flashmessages" />
+<f:render section="MainContent" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Partials/FormEditor/Stage/FileUploadTemplate.html b/typo3/sysext/form/Resources/Private/Backend/Partials/FormEditor/Stage/FileUploadTemplate.html
new file mode 100644
index 0000000000000000000000000000000000000000..7ded50d8f187f760a55fcad0a185d286a6d0aa71
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Partials/FormEditor/Stage/FileUploadTemplate.html
@@ -0,0 +1,33 @@
+<div class="meta-label">
+    <span data-template-property="_type"></span>: <span data-template-property="_identifier"></span>
+</div>
+
+<div class="t3-form-form-element-body">
+    <div class="t3-form-icon-container">
+        <span data-identifier="elementIcon"></span>
+    </div>
+
+    <div class="t3-form-element-info">
+        <div class="element-label-container">
+            <div class="element-label">
+                <span data-template-property="label"></span>
+                <span data-template-property="_required"></span>
+            </div>
+        </div>
+        <div class="element-content">
+            <div data-template-property="properties.saveToFileMount" />
+            <div data-identifier="multiValueContainer" data-template-property="properties.allowedMimeTypes">
+                <div data-template-property="_value" />
+            </div>
+        </div>
+    </div>
+
+    <div class="t3-form-validator-info" data-identifier="validators">
+        <span data-identifier="validatorIcon"></span>
+        <div class="t3-form-validator-list">
+            <div data-identifier="validatorsContainer">
+                <div class="validator-label" data-template-property="_label"></div>
+            </div>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Partials/FormEditor/Stage/SelectTemplate.html b/typo3/sysext/form/Resources/Private/Backend/Partials/FormEditor/Stage/SelectTemplate.html
new file mode 100644
index 0000000000000000000000000000000000000000..878e58060910a0dbe29e2d87d69138cd0a5132ff
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Partials/FormEditor/Stage/SelectTemplate.html
@@ -0,0 +1,32 @@
+<div class="meta-label">
+    <span data-template-property="_type"></span>: <span data-template-property="_identifier"></span>
+</div>
+
+<div class="t3-form-form-element-body">
+    <div class="t3-form-icon-container">
+        <span data-identifier="elementIcon"></span>
+    </div>
+
+    <div class="t3-form-element-info">
+        <div class="element-label-container">
+            <div class="element-label">
+                <span data-template-property="label"></span>
+                <span data-template-property="_required"></span>
+            </div>
+        </div>
+        <div class="element-content">
+            <div data-identifier="multiValueContainer" data-template-property="properties.options">
+                <div data-template-property="_label"></div>
+            </div>
+        </div>
+    </div>
+
+    <div class="t3-form-validator-info" data-identifier="validators">
+        <span data-identifier="validatorIcon"></span>
+        <div class="t3-form-validator-list">
+            <div data-identifier="validatorsContainer">
+                <div class="validator-label" data-template-property="_label"></div>
+            </div>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Partials/FormEditor/Stage/SimpleTemplate.html b/typo3/sysext/form/Resources/Private/Backend/Partials/FormEditor/Stage/SimpleTemplate.html
new file mode 100644
index 0000000000000000000000000000000000000000..c2a539144515d3eb181a8a67a346bd7a92f01a88
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Partials/FormEditor/Stage/SimpleTemplate.html
@@ -0,0 +1,27 @@
+<div class="meta-label">
+    <span data-template-property="_type"></span>: <span data-template-property="_identifier"></span>
+</div>
+
+<div class="t3-form-form-element-body">
+    <div class="t3-form-icon-container">
+        <span data-identifier="elementIcon"></span>
+    </div>
+
+    <div class="t3-form-element-info">
+        <div class="element-label-container">
+            <div class="element-label">
+                <span data-template-property="label"></span>
+                <span data-template-property="_required"></span>
+            </div>
+        </div>
+    </div>
+
+    <div class="t3-form-validator-info" data-identifier="validators">
+        <span data-identifier="validatorIcon"></span>
+        <div class="t3-form-validator-list">
+            <div data-identifier="validatorsContainer">
+                <div class="validator-label" data-template-property="_label"></div>
+            </div>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Index.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Index.html
new file mode 100644
index 0000000000000000000000000000000000000000..2dec63446d1a30afa8fb19a224998fb5b5b477db
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Index.html
@@ -0,0 +1,64 @@
+{namespace core = TYPO3\CMS\Core\ViewHelpers}
+
+<f:layout name="FormEditor" />
+
+<f:section name="ElementSidebarTree">
+    <div class="t3-form-x-component-inner-wrapper">
+        <div id="t3-form-navigation-component-tree-root-container" data-identifier="treeRootContainer">
+            <core:icon identifier="content-elements-mailform" />
+            <span id="t3-form-navigation-component-tree-root" data-identifier="treeRootElement"></span>
+        </div>
+        <div class="tree" data-identifier="structure-element"></div>
+        <div class="form-group col-sm-12">
+            <div class="btn-group btn-group-sm" role="group">
+                <a class="btn btn-default t3-form-element-new-page-button" href="#" title="{f:translate(key: 'LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.new_page_button')}" data-identifier="treeNewPageBottom"><core:icon identifier="actions-page-new" /> {f:translate(key: 'LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.new_page_button')}</a>
+            </div>
+        </div>
+    </div>
+</f:section>
+
+<f:section name="Header">
+    <h1><span id="t3-form-form-definition-label" data-identifier="formDefinitionLabel"></span></h1>
+</f:section>
+
+<f:section name="Stage">
+    <div class="panel panel-default" data-identifier="stagePanel">
+        <div class="panel-heading" data-identifier="panelHeading">
+            <span data-identifier="stageHeaderToolbar">
+                <div class="btn-group">
+                    <button class="btn btn-default" title="" data-identifier="buttonViewModePreview"><core:icon identifier="actions-document-view" alternativeMarkupIdentifier="inline" /></button>
+                    <button class="btn btn-default" title="" data-identifier="buttonViewModeAbstract"><core:icon identifier="actions-document-open" alternativeMarkupIdentifier="inline" /></button>
+                </div>
+                <div class="pull-right">
+                    <span class="paginiation-label" data-identifier="paginationTitle"></span>
+                    <div class="btn-group">
+                        <button class="btn btn-default" title="" data-identifier="buttonPaginationPrevious"><core:icon identifier="actions-view-paging-previous" alternativeMarkupIdentifier="inline" /></button>
+                        <button class="btn btn-default" title="" data-identifier="buttonPaginationNext"><core:icon identifier="actions-view-paging-next" alternativeMarkupIdentifier="inline" /></button>
+                    </div>
+                </div>
+            </span>
+        </div>
+        <div class="form-section" data-identifier="stageSection">
+            <div class="row">
+                <div id="t3-form-stage" class="form-group col-sm-12" data-identifier="stageArea"></div>
+            </div>
+            <div class="row" data-identifier="stageNewElementRow">
+                <div class="form-group col-sm-12">
+                    <div class="t3-form-new-element-container">
+                        <div class="btn-group btn-group-sm" role="group">
+                            <a class="btn btn-default" href="#" title="{f:translate(key: 'LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.stage.toolbar.new_element')}" data-identifier="stageNewElementBottom"><core:icon identifier="actions-document-new" /> {f:translate(key: 'LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.stage.toolbar.new_element')}</a>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</f:section>
+
+<f:section name="Inspector">
+    <div id="t3-form-inspector-panels">
+        <div class="t3-form-x-component-inner-wrapper">
+            <div id="t3-form-inspector" data-identifier="inspector"></div>
+        </div>
+    </div>
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/CheckboxEditor.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/CheckboxEditor.html
new file mode 100644
index 0000000000000000000000000000000000000000..40f29ea016b11f26fa2fdc36b68419dffe43f057
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/CheckboxEditor.html
@@ -0,0 +1,10 @@
+<div class="form-editor">
+    <div class="t3-form-control-group form-group">
+        <label>
+            <span data-template-property="label" />
+            <div class="t3-form-controls" data-identifier="inspectorEditorControlsWrapper">
+                <input type="checkbox" />
+            </div>
+        </label>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/CollectionElementHeaderEditor.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/CollectionElementHeaderEditor.html
new file mode 100644
index 0000000000000000000000000000000000000000..5c2c4649af05c26cc673a76c461b82c1746573dd
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/CollectionElementHeaderEditor.html
@@ -0,0 +1,5 @@
+<div class="t3-form-validator-editor">
+    <h4 data-template-property="header-label">
+        <span data-template-property="label" />
+    </h4>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/FinishersEditor.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/FinishersEditor.html
new file mode 100644
index 0000000000000000000000000000000000000000..1c0b4cb724df63c746b24ce674852e03b4a71233
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/FinishersEditor.html
@@ -0,0 +1,8 @@
+<div class="form-editor">
+    <h3><span data-template-property="label" /></h3>
+    <div id="t3-form-add-finisher" class="t3-form-add-collection-element">
+        <select data-template-property="selectOptions" class="form-control" />
+    </div>
+</div>
+<div id="t3-form-inspector-finishers" class="t3-form-collection-container" data-identifier="inspectorFinishers">
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/FormElementHeaderEditor.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/FormElementHeaderEditor.html
new file mode 100644
index 0000000000000000000000000000000000000000..fd3b22694747ead33a75b27d39e04f3f52c71b63
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/FormElementHeaderEditor.html
@@ -0,0 +1,3 @@
+<div class="form-editor">
+    <h2 class="t3-form-inspector-formelement-header-editor" data-template-property="header-label" data-identifier="inspectorFormElementHeaderEditor"></h2>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/PropertyGridEditor.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/PropertyGridEditor.html
new file mode 100644
index 0000000000000000000000000000000000000000..287b32d90f99e543c9ff496025fe5bd8b36d8d02
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/PropertyGridEditor.html
@@ -0,0 +1,47 @@
+{namespace core = TYPO3\CMS\Core\ViewHelpers}
+
+<div class="form-editor">
+    <div class="t3-form-control-group form-group property-grid">
+        <label><span data-template-property="label" /></label>
+        <div data-editor="new-property-grid" data-template-property="newPropertyPath">
+
+            <table class="table table-hover" data-identifier="propertyGridContainer">
+                <thead>
+                    <tr>
+                        <th></th>
+                        <th>Label</th>
+                        <th>Value</th>
+                        <th>Selected</th>
+                        <th></th>
+                    </tr>
+                </thead>
+                <tbody>
+                    <tr data-identifier="rowItem">
+                        <td><span class="sort-row-field" data-identifier="sortRow"><core:icon identifier="actions-move-move" /></span></td>
+                        <td><input type="text" class="form-control" value="" data-identifier="label" /></td>
+                        <td><input type="text" class="form-control" value="" data-identifier="value" /></td>
+                        <td><input type="checkbox" data-identifier="selectValue" /></td>
+                        <td>
+                            <div class="btn-group btn-group-sm" role="group">
+                                <button class="btn btn-default" title="Remove this row" data-identifier="deleteRow"><core:icon identifier="actions-delete" /></button>
+                            </div>
+                        </td>
+                    </tr>
+                    <tr data-identifier="addRowItem">
+                        <td>
+                            <div class="btn-group btn-group-sm" role="group">
+                                <button class="btn btn-default" title="Add a new row" data-identifier="addRow"><core:icon identifier="actions-add" /></button>
+                            </div>
+                        </td>
+                        <td></td>
+                        <td></td>
+                        <td></td>
+                        <td></td>
+                    </tr>
+                </tbody>
+            </table>
+
+        </div>
+        <div data-editor="property-grid" data-template-property="propertyPath" class="t3-form-grid" />
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/RemoveElementEditor.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/RemoveElementEditor.html
new file mode 100644
index 0000000000000000000000000000000000000000..afa20c43f2206876559274e6b77c76e61d7a3422
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/RemoveElementEditor.html
@@ -0,0 +1,5 @@
+{namespace core = TYPO3\CMS\Core\ViewHelpers}
+
+<div class="t3-form-control-group form-group btn-group-sm">
+    <button class="btn btn-default" title="Remove this Element"><core:icon identifier="actions-delete" alternativeMarkupIdentifier="inline"/></button>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/RequiredValidatorEditor.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/RequiredValidatorEditor.html
new file mode 100644
index 0000000000000000000000000000000000000000..40f29ea016b11f26fa2fdc36b68419dffe43f057
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/RequiredValidatorEditor.html
@@ -0,0 +1,10 @@
+<div class="form-editor">
+    <div class="t3-form-control-group form-group">
+        <label>
+            <span data-template-property="label" />
+            <div class="t3-form-controls" data-identifier="inspectorEditorControlsWrapper">
+                <input type="checkbox" />
+            </div>
+        </label>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/SingleSelectEditor.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/SingleSelectEditor.html
new file mode 100644
index 0000000000000000000000000000000000000000..f1f9653c5692b056bcb8711d024e0848fc0b8488
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/SingleSelectEditor.html
@@ -0,0 +1,6 @@
+<div class="t3-form-control-group form-group">
+    <label><span data-template-property="label" /></label>
+    <div class="t3-form-controls" data-identifier="inspectorEditorControlsWrapper">
+        <select data-template-property="selectOptions" class="form-control" />
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/TextEditor.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/TextEditor.html
new file mode 100644
index 0000000000000000000000000000000000000000..e74c2b2f4845d4cdceacca7071c86fb8cc91861b
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/TextEditor.html
@@ -0,0 +1,10 @@
+<div class="form-editor">
+    <div class="t3-form-control-group form-group">
+        <label><span data-template-property="label" /></label>
+        <div class="t3-form-controls" data-identifier="inspectorEditorControlsWrapper">
+            <input type="text" value="" data-template-property="propertyPath" class="form-control">
+            <span data-template-property="fieldExplanationText" />
+            <span data-template-property="validationErrors" />
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/TextareaEditor.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/TextareaEditor.html
new file mode 100644
index 0000000000000000000000000000000000000000..31e261e24a78b0a3b4e60d48411a277cefd14e66
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/TextareaEditor.html
@@ -0,0 +1,8 @@
+<div class="form-editor">
+    <div class="t3-form-control-group form-group">
+        <label><span data-template-property="label" /></label>
+        <div class="t3-form-controls" data-identifier="inspectorEditorControlsWrapper">
+            <textarea data-template-property="propertyPath" class="form-control" />
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/Typo3WinBrowserEditor.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/Typo3WinBrowserEditor.html
new file mode 100644
index 0000000000000000000000000000000000000000..66dd258bed107f2cdce40cb034a878024f3d595a
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/Typo3WinBrowserEditor.html
@@ -0,0 +1,17 @@
+<div class="form-editor">
+    <div class="t3-form-control-group form-group">
+        <label><span data-template-property="label" /></label>
+        <div class="t3-form-controls" data-identifier="inspectorEditorControlsWrapper">
+            <input type="text" value="" data-template-property="propertyPath" class="form-control" data-insert-target="">
+            <div class="help-block">
+                <a href="#" data-template-property="onclick" class="btn btn-default">
+                    <span class="t3js-icon icon icon-size-small icon-state-default icon-mimetypes-x-content-text" data-identifier="mimetypes-x-content-text">
+                        <span class="icon-markup" data-template-property="image" />
+                    </span> <span data-template-property="buttonLabel" />
+                </a>
+            </div>
+            <span data-template-property="fieldExplanationText" />
+            <span data-template-property="validationErrors" />
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/ValidatorsEditor.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/ValidatorsEditor.html
new file mode 100644
index 0000000000000000000000000000000000000000..6d61b5b0bf2376eb69a5eb13c60d8618b420bb45
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Inspector/ValidatorsEditor.html
@@ -0,0 +1,8 @@
+<div class="form-editor">
+    <h3><span data-template-property="label" /></h3>
+    <div id="t3-form-add-validator" class="t3-form-add-collection-element">
+        <select data-template-property="selectOptions" class="form-control" />
+    </div>
+</div>
+<div id="t3-form-inspector-validators" class="t3-form-collection-container" data-identifier="inspectorValidators">
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Modals/InsertElements.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Modals/InsertElements.html
new file mode 100644
index 0000000000000000000000000000000000000000..1d3c65f09421f3fd814c20a974a327023cd3ed80
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Modals/InsertElements.html
@@ -0,0 +1,30 @@
+{namespace core = TYPO3\CMS\Core\ViewHelpers}
+
+<div id="t3-form-insert-elements-panel">
+    <div class="t3-form-x-component-inner-wrapper">
+        <f:for each="{insertRenderablesPanelConfiguration}" as="insertRenderablePanelConfiguration">
+            <f:if condition="{insertRenderablePanelConfiguration.key} != 'page'">
+                <div class="row">
+                    <div class="col-sm-12">
+                        <h4 class="t3-form-group-{insertRenderablePanelConfiguration.key}">
+                            <span>{insertRenderablePanelConfiguration.label}</span>
+                        </h4>
+                    </div>
+                    <f:for each="{insertRenderablePanelConfiguration.elements}" as="element">
+                        <div class="col-sm-4 btn-group">
+                            <a class="t3-form-group-{insertRenderablePanelConfiguration.key} t3-form-type-{element.cssKey} btn btn-default btn-block" title="{element.key}" data-element-type="{element.key}">
+                                <span class="pull-left">
+                                    <core:icon identifier="{element.iconIdentifier}" alternativeMarkupIdentifier="inline" />
+                                    <span>{element.label}</span>
+                                </span>
+                                <span class="clearfix"></span>
+                            </a>
+                            <hr />
+                        </div>
+                    </f:for>
+                </div>
+                <hr />
+            </f:if>
+        </f:for>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Modals/InsertPages.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Modals/InsertPages.html
new file mode 100644
index 0000000000000000000000000000000000000000..2f4e0b90322a64463ed8087cbc63331a2a8dc7be
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Modals/InsertPages.html
@@ -0,0 +1,26 @@
+<div id="t3-form-insert-pages-panel">
+    <div class="t3-form-x-component-inner-wrapper">
+        <f:for each="{insertRenderablesPanelConfiguration}" as="insertRenderablePanelConfiguration">
+            <f:if condition="{insertRenderablePanelConfiguration.key} == 'page'">
+                <div class="row">
+                    <div class="col-sm-12">
+                        <h3 class="t3-form-group-{insertRenderablePanelConfiguration.key}">
+                            <span>{insertRenderablePanelConfiguration.label}</span>
+                        </h3>
+                    </div>
+                    <f:for each="{insertRenderablePanelConfiguration.elements}" as="element">
+                        <div class="col-sm-4 btn-group">
+                            <a class="t3-form-group-{insertRenderablePanelConfiguration.key} t3-form-type-{element.cssKey} btn btn-default btn-block" title="{element.key}" data-element-type="{element.key}">
+                                <span class="pull-left">
+                                    <core:icon identifier="{element.iconIdentifier}" alternativeMarkupIdentifier="inline" />
+                                    <span>{element.label}</span>
+                                 </span>
+                                <span class="clearfix"></span>
+                            </a>
+                            <hr />
+                        </div>
+                    </f:for>
+            </f:if>
+        </f:for>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Modals/ValidationErrors.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Modals/ValidationErrors.html
new file mode 100644
index 0000000000000000000000000000000000000000..24867aa45fe360dcd4ce14ec8bf563ef72537a77
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Modals/ValidationErrors.html
@@ -0,0 +1,17 @@
+<div id="t3-form-validation-errors-panel">
+    <div class="t3-form-x-component-inner-wrapper">
+        <div class="row">
+            <div class="col-sm-12">
+                <p><f:translate key="LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.modals.validationErrors.dialogMessage" /></p>
+            </div>
+
+            <div class="col-sm-12">
+                <dl class="t3-overview-list" data-identifier="rowsContainer">
+                    <dt data-identifier="rowItem">
+                        <i class="fa fa-exclamation-triangle text-danger" aria-hidden="true"></i>&nbsp;<a data-identifier="rowLink"></a>
+                    </dt>
+                </dl>
+            </div>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/AdvancedPassword.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/AdvancedPassword.html
new file mode 100644
index 0000000000000000000000000000000000000000..ececec82bde6c1a5aa7ce081876c347518d90406
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/AdvancedPassword.html
@@ -0,0 +1 @@
+<f:render partial="Stage/SimpleTemplate" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Checkbox.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Checkbox.html
new file mode 100644
index 0000000000000000000000000000000000000000..ececec82bde6c1a5aa7ce081876c347518d90406
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Checkbox.html
@@ -0,0 +1 @@
+<f:render partial="Stage/SimpleTemplate" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/ContentElement.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/ContentElement.html
new file mode 100644
index 0000000000000000000000000000000000000000..ac4e0dd62f978af5a4ee83b524131b3cbb3cc468
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/ContentElement.html
@@ -0,0 +1,30 @@
+<div class="meta-label">
+    <span data-template-property="_type"></span>: <span data-template-property="_identifier"></span>
+</div>
+
+<div class="t3-form-form-element-body">
+    <div class="t3-form-icon-container">
+        <span data-identifier="elementIcon"></span>
+    </div>
+
+    <div class="t3-form-element-info">
+        <div class="element-label-container">
+            <div class="element-label">
+                <span data-template-property="label"></span>
+                <span data-template-property="_required"></span>
+            </div>
+        </div>
+        <div class="element-content">
+            <div data-template-property="properties.contentElementUid" />
+        </div>
+    </div>
+
+    <div class="t3-form-validator-info" data-identifier="validators">
+        <span data-identifier="validatorIcon"></span>
+        <div class="t3-form-validator-list">
+            <div data-identifier="validatorsContainer">
+                <div class="validator-label" data-template-property="_label"></div>
+            </div>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/DatePicker.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/DatePicker.html
new file mode 100644
index 0000000000000000000000000000000000000000..ececec82bde6c1a5aa7ce081876c347518d90406
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/DatePicker.html
@@ -0,0 +1 @@
+<f:render partial="Stage/SimpleTemplate" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Fieldset.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Fieldset.html
new file mode 100644
index 0000000000000000000000000000000000000000..b4e6dcfeb6807178f5c0052de2bef1223010ca50
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Fieldset.html
@@ -0,0 +1,18 @@
+<div class="meta-label">
+    <span data-template-property="_type"></span>: <span data-template-property="_identifier"></span>
+</div>
+
+<div class="t3-form-form-element-body">
+    <div class="t3-form-icon-container">
+        <span data-identifier="elementIcon"></span>
+    </div>
+
+    <div class="t3-form-element-info">
+        <div class="element-label-container">
+            <div class="element-label">
+                <span data-template-property="label"></span>
+                <span data-template-property="_required"></span>
+            </div>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/FileUpload.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/FileUpload.html
new file mode 100644
index 0000000000000000000000000000000000000000..e476819a1f04275a6ae4b4dad1a388638e886514
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/FileUpload.html
@@ -0,0 +1 @@
+<f:render partial="Stage/FileUploadTemplate" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Hidden.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Hidden.html
new file mode 100644
index 0000000000000000000000000000000000000000..ececec82bde6c1a5aa7ce081876c347518d90406
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Hidden.html
@@ -0,0 +1 @@
+<f:render partial="Stage/SimpleTemplate" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/ImageUpload.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/ImageUpload.html
new file mode 100644
index 0000000000000000000000000000000000000000..e476819a1f04275a6ae4b4dad1a388638e886514
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/ImageUpload.html
@@ -0,0 +1 @@
+<f:render partial="Stage/FileUploadTemplate" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/MultiCheckbox.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/MultiCheckbox.html
new file mode 100644
index 0000000000000000000000000000000000000000..fbdd4da477ba9f597f5224f5c9cccebf141de1bb
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/MultiCheckbox.html
@@ -0,0 +1 @@
+<f:render partial="Stage/SelectTemplate" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/MultiSelect.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/MultiSelect.html
new file mode 100644
index 0000000000000000000000000000000000000000..fbdd4da477ba9f597f5224f5c9cccebf141de1bb
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/MultiSelect.html
@@ -0,0 +1 @@
+<f:render partial="Stage/SelectTemplate" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Page.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Page.html
new file mode 100644
index 0000000000000000000000000000000000000000..aa5e8817b998251bcebb536b7c01551f61f61439
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Page.html
@@ -0,0 +1 @@
+<h2 class="t3-form-page-title" data-template-property="label"></h2>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Password.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Password.html
new file mode 100644
index 0000000000000000000000000000000000000000..ececec82bde6c1a5aa7ce081876c347518d90406
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Password.html
@@ -0,0 +1 @@
+<f:render partial="Stage/SimpleTemplate" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/RadioButton.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/RadioButton.html
new file mode 100644
index 0000000000000000000000000000000000000000..fbdd4da477ba9f597f5224f5c9cccebf141de1bb
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/RadioButton.html
@@ -0,0 +1 @@
+<f:render partial="Stage/SelectTemplate" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/SingleSelect.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/SingleSelect.html
new file mode 100644
index 0000000000000000000000000000000000000000..fbdd4da477ba9f597f5224f5c9cccebf141de1bb
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/SingleSelect.html
@@ -0,0 +1 @@
+<f:render partial="Stage/SelectTemplate" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/StaticText.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/StaticText.html
new file mode 100644
index 0000000000000000000000000000000000000000..b9520b171c26bee4f44bef21bbe06d3f4a71b26b
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/StaticText.html
@@ -0,0 +1,30 @@
+<div class="meta-label">
+    <span data-template-property="_type"></span>: <span data-template-property="_identifier"></span>
+</div>
+
+<div class="t3-form-form-element-body">
+    <div class="t3-form-icon-container">
+        <span data-identifier="elementIcon"></span>
+    </div>
+
+    <div class="t3-form-element-info">
+        <div class="element-label-container">
+            <div class="element-label">
+                <span data-template-property="label"></span>
+                <span data-template-property="_required"></span>
+            </div>
+        </div>
+        <div class="element-content">
+            <div data-template-property="properties.text" />
+        </div>
+    </div>
+
+    <div class="t3-form-validator-info" data-identifier="validators">
+        <span data-identifier="validatorIcon"></span>
+        <div class="t3-form-validator-list">
+            <div data-identifier="validatorsContainer">
+                <div class="validator-label" data-template-property="_label"></div>
+            </div>
+        </div>
+    </div>
+</div>
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/SummaryPage.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/SummaryPage.html
new file mode 100644
index 0000000000000000000000000000000000000000..ccd6afd0873039d89ba683c61363fc428cebf7be
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/SummaryPage.html
@@ -0,0 +1 @@
+<h2 data-template-property="label"></h2>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Text.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Text.html
new file mode 100644
index 0000000000000000000000000000000000000000..ececec82bde6c1a5aa7ce081876c347518d90406
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Text.html
@@ -0,0 +1 @@
+<f:render partial="Stage/SimpleTemplate" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Textarea.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Textarea.html
new file mode 100644
index 0000000000000000000000000000000000000000..ececec82bde6c1a5aa7ce081876c347518d90406
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/Textarea.html
@@ -0,0 +1 @@
+<f:render partial="Stage/SimpleTemplate" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/_ElementToolbar.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/_ElementToolbar.html
new file mode 100644
index 0000000000000000000000000000000000000000..6b6f071ceb11105a7e2cf3167ecf314116af360b
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/_ElementToolbar.html
@@ -0,0 +1,35 @@
+{namespace core = TYPO3\CMS\Core\ViewHelpers}
+
+<div class="btn-toolbar-container" data-identifier="elementToolbar">
+    <div class="btn-toolbar" data-identifier="elementToolbarButtons">
+        <div class="btn-group btn-group-sm" role="group">
+            <a class="btn btn-default" href="#" title="{f:translate(key: 'LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.stage.toolbar.new_element')}" data-identifier="stageElementToolbarNewElement"><core:icon identifier="actions-document-new" alternativeMarkupIdentifier="inline" /></a>
+        </div>
+        <div class="btn-group btn-group-sm" role="group">
+            <div class="btn-group t3-form-dropdown-buttons" data-identifier="stageElementToolbarNewElementSplitButton">
+               <button type="button" class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false" title="{f:translate(key: 'LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.stage.toolbar.new_element')}">
+                   <core:icon identifier="actions-document-new" alternativeMarkupIdentifier="inline" />
+                   <span class="caret"></span>
+                   <span class="sr-only">Toggle Dropdown</span>
+               </button>
+               <ul class="dropdown-menu">
+                  <li data-no-sorting>
+                     <a href="#" data-identifier="stageElementToolbarNewElementSplitButtonInside">
+                         <core:icon identifier="t3-form-icon-insert-in" alternativeMarkupIdentifier="inline" />
+                         <f:translate key="LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.stage.toolbar.new_element.inside" />
+                     </a>
+                  </li>
+                  <li data-no-sorting>
+                     <a href="#" data-identifier="stageElementToolbarNewElementSplitButtonAfter">
+                         <core:icon identifier="t3-form-icon-insert-after" alternativeMarkupIdentifier="inline" />
+                         <f:translate key="LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.stage.toolbar.new_element.after" />
+                     </a>
+                  </li>
+               </ul>
+            </div>
+        </div>
+        <div class="btn-group btn-group-sm" role="group">
+            <a class="btn btn-default" href="#" title="{f:translate(key: 'LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.stage.toolbar.remove')}" data-identifier="stageElementToolbarRemoveElement"><core:icon identifier="actions-edit-delete" alternativeMarkupIdentifier="inline" /></a>
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/_UnknownElement.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/_UnknownElement.html
new file mode 100644
index 0000000000000000000000000000000000000000..31d9a2e7d15f6dac3d0eb2393d665899effbebdf
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Stage/_UnknownElement.html
@@ -0,0 +1 @@
+<span><f:translate key="LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.elements.UnknownElement" /></span>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Yaml/NewForms/BlankForm.yaml b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Yaml/NewForms/BlankForm.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5a1b08a10dccd7a9a199ebbda32550770e0e49a2
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Yaml/NewForms/BlankForm.yaml
@@ -0,0 +1,8 @@
+type: 'Form'
+identifier: 'blankForm'
+label: '[Blank Form]'
+renderables:
+    -
+        type: 'Page'
+        identifier: 'page-1'
+        label: 'Page'
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Yaml/NewForms/SimpleContactForm.yaml b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Yaml/NewForms/SimpleContactForm.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4e217ea03baca86c6fad60929cf6c47680927bae
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormEditor/Yaml/NewForms/SimpleContactForm.yaml
@@ -0,0 +1,75 @@
+identifier: ext-form-simple-contact-form-example
+label: 'Simple Contact Form'
+type: Form
+
+finishers:
+  -
+    identifier: EmailToReceiver
+    options:
+      subject: 'Your message: {subject}'
+      recipientAddress: 'your.company@example.com'
+      recipientName: 'Your Company name'
+      senderAddress: '{email}'
+      senderName: '{name}'
+      replyToAddress: ''
+      carbonCopyAddress: ''
+      blindCarbonCopyAddress: ''
+      format: 'html'
+      attachUploads: 'true'
+      translation:
+        language: ''
+
+renderables:
+  -
+    identifier: page-1
+    label: 'Contact Form'
+    type: Page
+
+    renderables:
+      -
+        identifier: name
+        label: 'Name'
+        type: Text
+        properties:
+          placeholder: 'Name'
+        defaultValue: ''
+        validators:
+          -
+            identifier: NotEmpty
+      -
+        identifier: subject
+        label: 'Subject'
+        type: Text
+        properties:
+          placeholder: 'Subject'
+        defaultValue: ''
+        validators:
+          -
+            identifier: NotEmpty
+      -
+        identifier: email
+        label: 'Email'
+        type: Text
+        properties:
+          placeholder: 'Email address'
+        defaultValue: ''
+        validators:
+          -
+            identifier: NotEmpty
+          -
+            identifier: EmailAddress
+      -
+        identifier: message
+        label: 'Message'
+        type: Textarea
+        properties:
+          placeholder: ''
+        defaultValue: ''
+        validators:
+          -
+            identifier: NotEmpty
+
+  -
+    identifier: summarypage
+    label: 'Summary page'
+    type: SummaryPage
diff --git a/typo3/sysext/form/Resources/Private/Backend/Templates/FormManager/Index.html b/typo3/sysext/form/Resources/Private/Backend/Templates/FormManager/Index.html
new file mode 100644
index 0000000000000000000000000000000000000000..cacc99f8dcdedec66b0ddaa2a0f27fa3fc2432fa
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Backend/Templates/FormManager/Index.html
@@ -0,0 +1,110 @@
+{namespace core = TYPO3\CMS\Core\ViewHelpers}
+
+<f:layout name="FormManager" />
+
+<f:section name="MainContent">
+    <script type="text/javascript">
+        require(['{dynamicRequireJsModules.app}', '{dynamicRequireJsModules.viewModel}'], function (formManagerApp, viewModel) {
+            var FORMMANAGER_APP = formManagerApp.getInstance(
+                <f:format.htmlentitiesDecode>{formManagerAppInitialData}</f:format.htmlentitiesDecode>,
+                viewModel
+            ).run();
+        });
+    </script>
+
+    <h1><f:translate key="LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.headline" /></h1>
+
+    <f:if condition="{forms}">
+        <f:then>
+            <div class="panel panel-space panel-default recordlist">
+                <div class="panel-heading">
+                    <span><f:translate key="LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.edit_existing_forms" /></span>
+                </div>
+                <div class="collapse in">
+                    <div class="table-fit">
+                        <table id="forms" class="table table-striped table-hover">
+                            <thead>
+                                <tr>
+                                    <th nowrap="nowrap" class="col-icon"><a class="btn btn-default" data-identifier="newForm" href="#"><core:icon identifier="actions-add" /></a></th>
+                                    <th nowrap="nowrap" class="col-title col-responsive"><f:translate key="LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.form_name" /></th>
+                                    <th nowrap="nowrap" class="col-control"></th>
+                                    <th nowrap="nowrap"><f:translate key="LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.location" /></th>
+                                    <th nowrap="nowrap"><f:translate key="LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.references" /></th>
+                                </tr>
+                            </thead>
+                            <tbody>
+                                <f:for each="{forms}" as="form">
+                                    <tr>
+                                        <td nowrap="nowrap" class="col-icon">
+                                            <f:if condition="{form.duplicateIdentifier}">
+                                                <f:then>
+                                                    <span title="{f:translate(key: 'LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.duplicate_identifier')} {form.identifier}" data-toggle="tooltip" data-placement="top">
+                                                        <core:icon identifier="overlay-missing" />
+                                                    </span>
+                                                </f:then>
+                                                <f:else>
+                                                    <span title="id={form.identifier}" data-toggle="tooltip" data-placement="right">
+                                                        <core:icon identifier="content-elements-mailform" />
+                                                    </span>
+                                                </f:else>
+                                            </f:if>
+                                        </td>
+                                        <td nowrap="nowrap" class="col-title col-responsive">
+                                            <f:if condition="{form.readOnly}">
+                                                <f:then>
+                                                    <div>{form.name}</div>
+                                                </f:then>
+                                                <f:else>
+                                                    <f:link.action controller="FormEditor" action="index" arguments="{formPersistenceIdentifier: form.persistenceIdentifier}" title="{f:translate(key: 'LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.edit_form')}" data="{toggle: 'tooltip', placement: 'right'}">{form.name}</f:link.action>
+                                                </f:else>
+                                            </f:if>
+
+                                        </td>
+                                        <td nowrap="nowrap" class="col-control">
+                                            <div class="btn-group" role="group">
+                                                <f:if condition="{form.readOnly}">
+                                                    <f:then>
+                                                        <button class="btn btn-default form-record-readonly" disabled="disabled" title="{f:translate(key: 'LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.edit_form_not_allowed')}"><core:icon identifier="actions-open" /></button>
+                                                    </f:then>
+                                                    <f:else>
+                                                        <f:link.action controller="FormEditor" action="index" arguments="{formPersistenceIdentifier: form.persistenceIdentifier}" title="{f:translate(key: 'LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.edit_form')}" class="btn btn-default form-record-open"><core:icon identifier="actions-open" /></f:link.action>
+                                                    </f:else>
+                                                </f:if>
+                                                <a href="#" data-identifier="duplicateForm" data-form-persistence-identifier="{form.persistenceIdentifier}" data-form-name="{form.name}" title="{f:translate(key: 'LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.duplicate_this_form')}" class="btn btn-default form-record-duplicate"><core:icon identifier="t3-form-icon-duplicate" /></a>
+                                                <f:if condition="{form.location} === 'storage'">
+                                                    <f:then>
+                                                        <a href="#" data-identifier="removeForm" data-form-persistence-identifier="{form.persistenceIdentifier}" title="{f:translate(key: 'LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.delete_form')}" class="btn btn-default form-record-delete"><core:icon identifier="actions-edit-delete" /></a>
+                                                    </f:then>
+                                                    <f:else>
+                                                        <button class="btn btn-default form-record-delete" disabled="disabled" title="{f:translate(key: 'LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.delete_form_not_allowed')}"><core:icon identifier="actions-edit-delete" /></button>
+                                                    </f:else>
+                                                </f:if>
+                                            </div>
+                                        </td>
+                                        <td nowrap="nowrap">{form.persistenceIdentifier}</td>
+                                        <td nowrap="nowrap">
+                                            <f:if condition="{form.referenceCount}">
+                                                <f:then>
+                                                    <a href="#" data-identifier="showReferences" data-form-persistence-identifier="{form.persistenceIdentifier}" data-form-name="{form.name}">{form.referenceCount}</a>
+                                                </f:then>
+                                                <f:else>
+                                                    {form.referenceCount}
+                                                </f:else>
+                                            </f:if>
+                                        </td>
+                                    </tr>
+                                </f:for>
+                            </tbody>
+                        </table>
+                    </div>
+                </div>
+            </div>
+        </f:then>
+        <f:else>
+            <f:be.infobox title="{f:translate(key: 'formManager.no_forms', extensionName:'form')}" state="-1">
+                <p><f:translate key="LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.no_forms"/></p>
+                <a class="btn btn-primary" data-identifier="newForm" href="#"><f:translate key="LLL:EXT:form/Resources/Private/Language/Database.xlf:formManager.create_new_form"/></a>
+            </f:be.infobox>
+        </f:else>
+    </f:if>
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Layouts/FormElements/Field.html b/typo3/sysext/form/Resources/Private/Frontend/Layouts/FormElements/Field.html
new file mode 100644
index 0000000000000000000000000000000000000000..0002b904387d387d1e92aedf7ed509c9a0592cc8
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Layouts/FormElements/Field.html
@@ -0,0 +1,22 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<div class="form-group">
+    <label for="{element.uniqueIdentifier}">{formvh:translateElementProperty(element: element, property: 'label')}<f:if condition="{element.required}"><f:render partial="Field/Required" /></f:if></label>
+    <div class="{element.properties.containerClassAttribute}">
+        <f:render section="field" />
+        <f:format.raw>
+            <f:form.validationResults for="{element.identifier}">
+                <f:if condition="{validationResults.flattenedErrors}">
+                    <span class="form-control-feedback error help-inline">
+                        <f:for each="{validationResults.errors}" as="error">
+                            {error -> f:translate(key: '{element.renderingOptions.translation.translationFile}:validation.error.{error.code}', arguments: error.arguments)}
+                            <br />
+                        </f:for>
+                    </span>
+                </f:if>
+            </f:form.validationResults>
+        </f:format.raw>
+        <f:if condition="{element.properties.elementDescription}">
+            <span class="help-block">{formvh:translateElementProperty(element: element, property: 'elementDescription')}</span>
+        </f:if>
+    </div>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Partials/FormElements/Field/Required.html b/typo3/sysext/form/Resources/Private/Frontend/Partials/FormElements/Field/Required.html
new file mode 100644
index 0000000000000000000000000000000000000000..b8618a87e9c68bb89d5b9284545437dfa406ce2e
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Partials/FormElements/Field/Required.html
@@ -0,0 +1 @@
+<span class="required">*</span>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Partials/FormElements/Form/Navigation.html b/typo3/sysext/form/Resources/Private/Frontend/Partials/FormElements/Form/Navigation.html
new file mode 100644
index 0000000000000000000000000000000000000000..154f80c5eed151b7ef0790aa49f9a89b026cdea0
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Partials/FormElements/Form/Navigation.html
@@ -0,0 +1,25 @@
+<nav class="form-navigation">
+    <div class="btn-toolbar" role="toolbar">
+        <div class="btn-group" role="group">
+            <f:if condition="{form.previousPage}">
+                <span class="previous">
+                    <f:form.button property="__currentPage" value="{form.previousPage.index}" class="btn btn-cancel">{formvh:translateElementProperty(element: form.currentPage, renderingOptionProperty: 'previousButtonLabel')}</f:form.button>
+                </span>
+            </f:if>
+            <f:if condition="{form.nextPage}">
+                <f:then>
+                    <span class="next">
+                        <f:form.button property="__currentPage" value="{form.nextPage.index}" class="btn btn-primary">{formvh:translateElementProperty(element: form.currentPage, renderingOptionProperty: 'nextButtonLabel')}</f:form.button>
+                    </span>
+                </f:then>
+                <f:else>
+                    <span class="next submit">
+                        <f:form.button property="__currentPage" value="{form.pages -> f:count()}" class="btn btn-primary">
+                            {formvh:translateElementProperty(element: form, renderingOptionProperty: 'submitButtonLabel')}
+                        </f:form.button>
+                    </span>
+                </f:else>
+            </f:if>
+        </div>
+    </div>
+</nav>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/Finishers/Email/Html.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/Finishers/Email/Html.html
new file mode 100644
index 0000000000000000000000000000000000000000..dce25de4ddadeb9d16e9087d570a413baa51157a
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/Finishers/Email/Html.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+
+<html>
+<head>
+    <title></title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    <meta name="format-detection" content="telephone=no">
+</head>
+
+<body>
+    <table width="600" cellpadding="0" cellspacing="0" border="0">
+        <formvh:renderAllFormValues renderable="{form.formDefinition}" formRuntime="{form}">
+            <tr>
+                <td width="600" valign="top" align="left">{formvh:translateElementProperty(element: formValue.element, property: 'label', formRuntime: form)}</td>
+                <td width="600" valign="top" align="left">
+                    <f:if condition="{formValue.value}">
+                        <f:then>
+                            <f:if condition="{formValue.isMultiValue}">
+                                <f:then>
+                                    <table cellspacing="0" border="0">
+                                        <f:for each="{formValue.processedValue}" as="value">
+                                            <tr>
+                                                <td>{value}</td>
+                                            </tr>
+                                        </f:for>
+                                    </table>
+                                </f:then>
+                                <f:else>
+                                    <table cellspacing="0" border="0">
+                                        <tr>
+                                            <td>{formValue.processedValue}</td>
+                                        </tr>
+                                    </table>
+                                </f:else>
+                            </f:if>
+                        </f:then>
+                        <f:else>
+                            -
+                        </f:else>
+                    </f:if>
+                </td>
+            </tr>
+        </formvh:renderAllFormValues>
+    </table>
+</body>
+</html>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/Finishers/Email/Plaintext.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/Finishers/Email/Plaintext.html
new file mode 100644
index 0000000000000000000000000000000000000000..05cde5a0bf8444411d2f486b97130930d5953d44
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/Finishers/Email/Plaintext.html
@@ -0,0 +1,3 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+
+<formvh:renderAllFormValues renderable="{form.formDefinition}" formRuntime="{form}"><formvh:plainTextMail formValue="{formValue}" formRuntime="{form}" /></formvh:renderAllFormValues>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/AdvancedPassword.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/AdvancedPassword.html
new file mode 100644
index 0000000000000000000000000000000000000000..05a9f1da31cbd421f6ae6aa92f60e28fc42fd0f9
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/AdvancedPassword.html
@@ -0,0 +1,28 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<f:layout name="Field" />
+<f:section name="field">
+    <div class="form-group">
+        <f:form.password
+                property="{element.identifier}.password"
+                id="{element.uniqueIdentifier}"
+                class="{element.properties.elementClassAttribute} form-control"
+                errorClass="{element.properties.elementErrorClassAttribute}"
+                additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\', placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}', else: '{placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}')}"
+        />
+        <f:if condition="{formvh:translateElementProperty(element: element, property: 'passwordDescription')}">
+            <span class="help-block">{formvh:translateElementProperty(element: element, property: 'passwordDescription')}</span>
+        </f:if>
+    </div>
+    <div class="form-group">
+        <f:if condition="{formvh:translateElementProperty(element: element, property: 'confirmationLabel')}">
+            <label for="{element.uniqueIdentifier}-confirmation">{formvh:translateElementProperty(element: element, property: 'confirmationLabel')}<f:if condition="{element.required}"><f:render partial="Field/Required" /></f:if></label>
+        </f:if>
+        <f:form.password
+                property="{element.identifier}.confirmation"
+                id="{element.uniqueIdentifier}-confirmation"
+                class="{element.properties.confirmationClassAttribute} form-control"
+                errorClass="{element.properties.elementErrorClassAttribute}"
+                additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\', placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}', else: '{placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}')}"
+        />
+    </div>
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Checkbox.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Checkbox.html
new file mode 100644
index 0000000000000000000000000000000000000000..61e96d2271edf5e1b02cc38dfd2bee0ddfaa81c3
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Checkbox.html
@@ -0,0 +1,15 @@
+<f:layout name="Field" />
+<f:section name="field">
+    <div class="form-check">
+        <label class="{element.properties.elementClassAttribute} form-check-label">
+            <f:form.checkbox
+                    property="{element.identifier}"
+                    id="{element.uniqueIdentifier}"
+                    class="{element.properties.elementClassAttribute}"
+                    value="{element.properties.value}"
+                    errorClass="{element.properties.elementErrorClassAttribute}"
+                    additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\'}')}"
+            />
+        </label>
+    </div>
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/ContentElement.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/ContentElement.html
new file mode 100644
index 0000000000000000000000000000000000000000..9d1b2d4bb23bd2e467ad6dc4bed4a55bb4a98cd9
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/ContentElement.html
@@ -0,0 +1,22 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<f:if condition="{element.rootForm.renderingOptions.previewMode}">
+    <f:then>
+        <div class="clearfix">
+            <f:if condition="{element.properties.contentElementUid}">
+                <f:then>
+                    <formvh:be.renderContentElementPreview contentElementUid="{element.properties.contentElementUid}" />
+                </f:then>
+                <f:else>
+                    <f:translate key="LLL:EXT:form/Resources/Private/Language/Database.xlf:formEditor.elements.ContentElement.selectContentElement" />
+                </f:else>
+            </f:if>
+        </div>
+    </f:then>
+    <f:else>
+        <f:if condition="{element.properties.contentElementUid}">
+            <div class="clearfix{f:if(condition: element.properties.elementClassAttribute, then: ' {element.properties.elementClassAttribute}')}">
+                <f:cObject typoscriptObjectPath="lib.tx_form.contentElementRendering">{element.properties.contentElementUid}</f:cObject>
+            </div>
+        </f:if>
+    </f:else>
+</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/DatePicker.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/DatePicker.html
new file mode 100644
index 0000000000000000000000000000000000000000..b1a4e4d93c738e9814263cd7c41b9b8bfc2b9ead
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/DatePicker.html
@@ -0,0 +1,47 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<f:layout name="Field" />
+<f:section name="field">
+    <formvh:form.datePicker
+        id="{element.uniqueIdentifier}"
+        property="{element.identifier}"
+        placeholder="{formvh:translateElementProperty(element: element, property: 'placeholder')}"
+        dateFormat="{element.properties.dateFormat}"
+        initialDate="{element.properties.initialDate}"
+        enableDatePicker="{element.properties.enableDatePicker}"
+        class="{element.properties.elementClassAttribute}"
+        errorClass="{element.properties.elementErrorClassAttribute}"
+        additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\'}')}"
+    >
+        <f:if condition="{element.rootForm.renderingOptions.previewMode}">
+            <f:else>
+                <f:if condition="{element.properties.enableDatePicker}">
+                    <script type="text/javascript">
+                        if ("undefined" !== typeof $) {
+                            $(function() {
+                                $("#<f:format.raw>{element.uniqueIdentifier}</f:format.raw>").datepicker({
+                                    dateFormat: "<f:format.raw>{datePickerDateFormat}</f:format.raw>"
+                                }).on("keydown", function(e) {
+                                    // By using "backspace" or "delete", you can clear the datepicker again.
+                                    if(e.keyCode == 8 || e.keyCode == 46) {
+                                        e.preventDefault();
+                                        $.datepicker._clearDate(this);
+                                    }
+                                });
+                            });
+                        }
+                    </script>
+                </f:if>
+            </f:else>
+        </f:if>
+    </formvh:form.datePicker>
+
+    <f:if condition="{element.properties.displayTimeSelector}">
+        <formvh:form.timePicker
+                id="{element.uniqueIdentifier}-time"
+                property="{element.identifier}"
+                initialDate="{element.properties.initialDate}"
+                class="{element.properties.timeSelectorClassAttribute} form-control"
+                errorClass="{element.properties.elementErrorClassAttribute}"
+        />
+    </f:if>
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Fieldset.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Fieldset.html
new file mode 100644
index 0000000000000000000000000000000000000000..89c64c46685e54820f1f2321d0154dfb652199a9
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Fieldset.html
@@ -0,0 +1,9 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<fieldset id="{section.uniqueIdentifier}" class="form-group{f:if(condition: section.properties.elementClassAttribute, then: ' {section.properties.elementClassAttribute}')}">
+    <f:if condition="{section.label}">
+        <legend>{formvh:translateElementProperty(element: section, property: 'label')}</legend>
+    </f:if>
+    <f:for each="{section.elements}" as="element">
+        <formvh:renderRenderable renderable="{element}" />
+    </f:for>
+</fieldset>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/FileUpload.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/FileUpload.html
new file mode 100644
index 0000000000000000000000000000000000000000..d2774bec03705fa23061b1b20d0a8c325f120cd5
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/FileUpload.html
@@ -0,0 +1,11 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<f:layout name="Field" />
+<f:section name="field">
+    <formvh:form.uploadedResource property="{element.identifier}" as="resource" additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\'}')}" accept="{element.properties.allowedMimeTypes}">
+        <f:if condition="{resource}">
+            <div id="{element.uniqueIdentifier}-preview">
+                {resource.originalResource.originalFile.name}
+            </div>
+        </f:if>
+    </formvh:form.uploadedResource>
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Form.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Form.html
new file mode 100644
index 0000000000000000000000000000000000000000..e4c950a565bec8fc882955b76732df4c042c5b2a
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Form.html
@@ -0,0 +1,7 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<formvh:form object="{form}" action="perform" method="post" id="{form.identifier}" section="{form.identifier}" enctype="multipart/form-data">
+    <formvh:renderRenderable renderable="{form.currentPage}" />
+    <div class="actions">
+        <f:render partial="Form/Navigation" arguments="{form: form}" />
+    </div>
+</formvh:form>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Hidden.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Hidden.html
new file mode 100644
index 0000000000000000000000000000000000000000..0d4b716824f788d164a9d639ae5c5b12b7ea4fcb
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Hidden.html
@@ -0,0 +1 @@
+<f:form.hidden property="{element.identifier}" id="{element.uniqueIdentifier}" value="{element.properties.value}" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Honeypot.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Honeypot.html
new file mode 100644
index 0000000000000000000000000000000000000000..6f26f34f07d38a00221846938f814d8db14cb54e
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Honeypot.html
@@ -0,0 +1,8 @@
+<f:if condition="{element.properties.renderAsHiddenField}">
+    <f:then>
+        <f:form.hidden property="{element.identifier}" id="{element.uniqueIdentifier}" additionalAttributes="{autocomplete: 'off'}" />
+    </f:then>
+    <f:else>
+        <f:form.textfield property="{element.identifier}" id="{element.uniqueIdentifier}" class="{element.properties.elementClassAttribute}" additionalAttributes="{autocomplete: 'off'}" style="{element.properties.styleAttribute}" />
+    </f:else>
+</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/ImageUpload.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/ImageUpload.html
new file mode 100644
index 0000000000000000000000000000000000000000..3c6798a59d5575695285f3cfab9d69bd6d5c03dc
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/ImageUpload.html
@@ -0,0 +1,13 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<f:layout name="Field" />
+<f:section name="field">
+    <formvh:form.uploadedResource property="{element.identifier}" as="image" additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\'}')}" accept="{element.properties.allowedMimeTypes}">
+        <f:if condition="{image}">
+            <div id="{element.uniqueIdentifier}-preview">
+                <a href="{f:uri.image(image: image, maxWidth: element.properties.imageLinkMaxWidth)}" class="{element.properties.elementClassAttribute}">
+                    <f:image image="{image}" maxWidth="{element.properties.imageMaxWidth}" maxHeight="{element.properties.imageMaxHeight}" alt="{formvh:translateElementProperty(element: element, property: 'altText')}" />
+                </a>
+            </div>
+        </f:if>
+    </formvh:form.uploadedResource>
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/MultiCheckbox.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/MultiCheckbox.html
new file mode 100644
index 0000000000000000000000000000000000000000..642dcdf1c6bceb3f5782e6c0b220737cc2030b30
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/MultiCheckbox.html
@@ -0,0 +1,20 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<f:layout name="Field" />
+<f:section name="field">
+    <div id="{element.uniqueIdentifier}" class="inputs-list">
+        <f:for each="{element.properties.options}" as="label" key="value">
+            <div class="form-check">
+                <label class="form-check-label">
+                    <formvh:form.checkbox
+                            property="{element.identifier}"
+                            multiple="1"
+                            class="{element.properties.elementClassAttribute}"
+                            value="{value}"
+                            errorClass="{element.properties.elementErrorClassAttribute}"
+                    />
+                    <span>{formvh:translateElementProperty(element: element, property: 'options.{value}')}</span>
+                </label>
+            </div>
+        </f:for>
+    </div>
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/MultiSelect.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/MultiSelect.html
new file mode 100644
index 0000000000000000000000000000000000000000..c8459427292dd471cc741414148bdfe665c7ab0a
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/MultiSelect.html
@@ -0,0 +1,12 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<f:layout name="Field" />
+<f:section name="field">
+    <f:form.select
+            property="{element.identifier}"
+            id="{element.uniqueIdentifier}"
+            class="{element.properties.elementClassAttribute} form-control"
+            options="{formvh:translateElementProperty(element: element, property: 'options')}"
+            multiple="multiple"
+            errorClass="{element.properties.elementErrorClassAttribute}"
+    />
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Page.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Page.html
new file mode 100644
index 0000000000000000000000000000000000000000..cf7462f4bec952a5e439bd404b62adc11e35e996
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Page.html
@@ -0,0 +1,9 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<fieldset class="form-group">
+    <f:if condition="{page.label}">
+        <legend>{formvh:translateElementProperty(element: page, property: 'label')}</legend>
+    </f:if>
+    <f:for each="{page.elements}" as="element">
+        <formvh:renderRenderable renderable="{element}" />
+    </f:for>
+</fieldset>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Password.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Password.html
new file mode 100644
index 0000000000000000000000000000000000000000..89f7780705b9d475cb11045169ae7d57a5340f39
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Password.html
@@ -0,0 +1,11 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<f:layout name="Field" />
+<f:section name="field">
+    <f:form.password
+            property="{element.identifier}"
+            id="{element.uniqueIdentifier}"
+            class="{element.properties.elementClassAttribute} form-control"
+            additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\', placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}', else: '{placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}')}"
+            errorClass="{element.properties.elementErrorClassAttribute}"
+    />
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/RadioButton.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/RadioButton.html
new file mode 100644
index 0000000000000000000000000000000000000000..7434e45b94200df66e76e1e47245921e72344b02
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/RadioButton.html
@@ -0,0 +1,22 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<f:layout name="Field" />
+<f:section name="field">
+    <div id="{element.uniqueIdentifier}" class="inputs-list">
+        <div class="form-group">
+            <f:for each="{element.properties.options}" as="label" key="value">
+                <div class="form-check">
+                    <label class="form-check-label">
+                        <f:form.radio
+                                property="{element.identifier}"
+                                class="{element.properties.elementClassAttribute} form-check-input"
+                                value="{value}"
+                                errorClass="{element.properties.elementErrorClassAttribute}"
+                                additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\'}')}"
+                        />
+                        <span>{formvh:translateElementProperty(element: element, property: 'options.{value}')}</span>
+                    </label>
+                </div>
+            </f:for>
+        </div>
+    </div>
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/SingleSelect.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/SingleSelect.html
new file mode 100644
index 0000000000000000000000000000000000000000..bb125dc15aed99a1e27c4ea9ef02dac2b6cdcbd6
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/SingleSelect.html
@@ -0,0 +1,12 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<f:layout name="Field" />
+<f:section name="field">
+    <f:form.select
+            property="{element.identifier}"
+            id="{element.uniqueIdentifier}"
+            options="{formvh:translateElementProperty(element: element, property: 'options')}"
+            class="{element.properties.elementClassAttribute} form-control"
+            errorClass="{element.properties.elementErrorClassAttribute}"
+            additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\'}')}"
+    />
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/StaticText.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/StaticText.html
new file mode 100644
index 0000000000000000000000000000000000000000..9fe0a2a9ef5597bf408ea1e9dc7a9d334beb06c2
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/StaticText.html
@@ -0,0 +1,9 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<div class="clearfix">
+    <f:if condition="{element.label}">
+        <h2>{formvh:translateElementProperty(element: element, property: 'label')}</h2>
+    </f:if>
+    <f:if condition="{element.properties.text}">
+        <p{f:if(condition: element.properties.elementClassAttribute, then: ' class="{element.properties.elementClassAttribute}"')}>{formvh:translateElementProperty(element: element, property: 'text') -> f:format.nl2br()}</p>
+    </f:if>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/SummaryPage.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/SummaryPage.html
new file mode 100644
index 0000000000000000000000000000000000000000..3afa995f48a0e60f613bda6e9933245613b1e4fc
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/SummaryPage.html
@@ -0,0 +1,43 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<fieldset class="form-group">
+    <f:if condition="{page.label}">
+        <legend>{formvh:translateElementProperty(element: page, property: 'label')}</legend>
+    </f:if>
+    <div class="table-responsive">
+        <table class="table">
+            <formvh:renderAllFormValues renderable="{page.rootForm}">
+                <tr>
+                    <td class="summary-table-first-col">{formvh:translateElementProperty(element: formValue.element, property: 'label')}</td>
+                    <td>
+                        <f:if condition="{formValue.value}">
+                            <f:then>
+                                <f:if condition="{0: formValue.element.type} == {0: 'ImageUpload'}">
+                                    <f:then>
+                                        <f:image image="{formValue.value}" maxWidth="{formValue.element.properties.imageMaxWidth}" maxHeight="{formValue.element.properties.imageMaxHeight}" alt="{formvh:translateElementProperty(element: formValue.element, property: 'altText')}" />
+                                    </f:then>
+                                    <f:else>
+                                        <f:if condition="{formValue.isMultiValue}">
+                                            <f:then>
+                                                <ul>
+                                                    <f:for each="{formValue.processedValue}" as="value">
+                                                        <li>{value}</li>
+                                                    </f:for>
+                                                </ul>
+                                            </f:then>
+                                            <f:else>
+                                                {formValue.processedValue}
+                                            </f:else>
+                                        </f:if>
+                                    </f:else>
+                                </f:if>
+                            </f:then>
+                            <f:else>
+                                -
+                            </f:else>
+                        </f:if>
+                    </td>
+                </tr>
+            </formvh:renderAllFormValues>
+        </table>
+    </div>
+</fieldset>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Text.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Text.html
new file mode 100644
index 0000000000000000000000000000000000000000..0eb10c2c1b8b1964902ed7ebc5c851866b6bf686
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Text.html
@@ -0,0 +1,12 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<f:layout name="Field" />
+<f:section name="field">
+    <f:form.textfield
+            property="{element.identifier}"
+            id="{element.uniqueIdentifier}"
+            class="{element.properties.elementClassAttribute} form-control"
+            placeholder="{formvh:translateElementProperty(element: element, property: 'placeholder')}"
+            errorClass="{element.properties.elementErrorClassAttribute}"
+            required="{element.required}"
+    />
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Textarea.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Textarea.html
new file mode 100644
index 0000000000000000000000000000000000000000..c0baddec26b081a971e5bcf8edc236b775f9e98c
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/FormElements/Textarea.html
@@ -0,0 +1,13 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<f:layout name="Field" />
+<f:section name="field">
+    <f:form.textarea
+            property="{element.identifier}"
+            id="{element.uniqueIdentifier}"
+            class="{element.properties.elementClassAttribute} form-control"
+            rows="{element.properties.rows}"
+            cols="{element.properties.cols}"
+            errorClass="{element.properties.elementErrorClassAttribute}"
+            additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\', placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}', else: '{placeholder: \'{formvh:translateElementProperty(element: element, property: \"placeholder\")}\'}')}"
+    />
+</f:section>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Frontend/Templates/Render.html b/typo3/sysext/form/Resources/Private/Frontend/Templates/Render.html
new file mode 100644
index 0000000000000000000000000000000000000000..a42a55d1682a7bd5352e41605d9658ed12c574c5
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Frontend/Templates/Render.html
@@ -0,0 +1,5 @@
+{namespace formvh=TYPO3\CMS\Form\ViewHelpers}
+<f:flashMessages class="flashmessages" />
+<f:if condition="{formConfiguration}">
+    <formvh:render overrideConfiguration="{formConfiguration}"/>
+</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Language/Database.xlf b/typo3/sysext/form/Resources/Private/Language/Database.xlf
index 069dedb784318e97a8a851d311e8572bfd1648a4..3f8d42d814994f9ce1e41dbcae87ed6d369fccc9 100644
--- a/typo3/sysext/form/Resources/Private/Language/Database.xlf
+++ b/typo3/sysext/form/Resources/Private/Language/Database.xlf
@@ -1,14 +1,690 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <xliff version="1.0" xmlns:t3="http://typo3.org/schemas/xliff">
-	<file t3:id="1450450398" source-language="en" datatype="plaintext" original="messages" date="2015-12-18T15:53:55Z" product-name="form">
-		<header/>
-		<body>
-			<trans-unit id="tx_form_predefinedform">
-				<source>Predefined form</source>
-			</trans-unit>
-			<trans-unit id="tx_form_predefinedform.selectPredefinedForm">
-				<source>Choose a predefined form</source>
-			</trans-unit>
-		</body>
-	</file>
+    <file t3:id="1471786343" source-language="en" datatype="plaintext" original="messages" date="2016-08-21T20:15:32Z" product-name="form">
+        <header/>
+        <body>
+            <trans-unit id="module.shortcut_name" xml:space="preserve">
+                <source>Form manager</source>
+            </trans-unit>
+
+            <trans-unit id="tt_content.pi_flexform.formframework.persistenceIdentifier" xml:space="preserve">
+                <source>Form definition</source>
+            </trans-unit>
+            <trans-unit id="tt_content.pi_flexform.formframework.sheet_general" xml:space="preserve">
+                <source>General</source>
+            </trans-unit>
+            <trans-unit id="tt_content.pi_flexform.formframework.selectPersistenceIdentifier" xml:space="preserve">
+                <source>Please select a form definition</source>
+            </trans-unit>
+            <trans-unit id="tt_content.pi_flexform.formframework.overrideFinishers" xml:space="preserve">
+                <source>Override finisher settings</source>
+            </trans-unit>
+
+            <trans-unit id="tt_content.finishersDefinition.EmailToSender.label" xml:space="preserve">
+                <source>Email to sender</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToSender.subject.label" xml:space="preserve">
+                <source>Subject of the email</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToSender.recipientAddress.label" xml:space="preserve">
+                <source>Email address of the recipient</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToSender.recipientName.label" xml:space="preserve">
+                <source>Human-readable name of the recipient</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToSender.senderAddress.label" xml:space="preserve">
+                <source>Email address of the sender</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToSender.senderName.label" xml:space="preserve">
+                <source>Human-readable name of the sender</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToSender.replyToAddress.label" xml:space="preserve">
+                <source>Email address of to be used as reply-to email</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToSender.carbonCopyAddress.label" xml:space="preserve">
+                <source>Email address of the copy recipient</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToSender.blindCarbonCopyAddress.label" xml:space="preserve">
+                <source>Email address of the blind copy recipient</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToSender.format.label" xml:space="preserve">
+                <source>The format of the email</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToSender.format.1" xml:space="preserve">
+                <source>HTML</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToSender.format.2" xml:space="preserve">
+                <source>Plain text</source>
+            </trans-unit>
+
+            <trans-unit id="tt_content.finishersDefinition.EmailToReceiver.label" xml:space="preserve">
+                <source>Email to receiver</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToReceiver.subject.label" xml:space="preserve">
+                <source>Subject of the email</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToReceiver.recipientAddress.label" xml:space="preserve">
+                <source>Email address of the recipient</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToReceiver.recipientName.label" xml:space="preserve">
+                <source>Human-readable name of the recipient</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToReceiver.senderAddress.label" xml:space="preserve">
+                <source>Email address of the sender</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToReceiver.senderName.label" xml:space="preserve">
+                <source>Human-readable name of the sender</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToReceiver.replyToAddress.label" xml:space="preserve">
+                <source>Email address of to be used as reply-to email</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToReceiver.carbonCopyAddress.label" xml:space="preserve">
+                <source>Email address of the copy recipient</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToReceiver.blindCarbonCopyAddress.label" xml:space="preserve">
+                <source>Email address of the blind copy recipient</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToReceiver.format.label" xml:space="preserve">
+                <source>Format of the email</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToReceiver.format.1" xml:space="preserve">
+                <source>HTML</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToReceiver.format.2" xml:space="preserve">
+                <source>Plain text</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToReceiver.language.label" xml:space="preserve">
+                <source>Translation language</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.EmailToReceiver.language.1" xml:space="preserve">
+                <source>Default</source>
+            </trans-unit>
+
+            <trans-unit id="tt_content.finishersDefinition.Redirect.label" xml:space="preserve">
+                <source>Redirect</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.Redirect.pageUid.label" xml:space="preserve">
+                <source>Page</source>
+            </trans-unit>
+            <trans-unit id="tt_content.finishersDefinition.Redirect.additionalParameters.label" xml:space="preserve">
+                <source>Additional link parameter</source>
+            </trans-unit>
+
+            <trans-unit id="formManagerController.deleteAction.error.title" xml:space="preserve">
+                <source>Delete error</source>
+            </trans-unit>
+            <trans-unit id="formManagerController.deleteAction.error.body" xml:space="preserve">
+                <source>The form "%s" could not be deleted.</source>
+            </trans-unit>
+
+            <trans-unit id="formManager.headline" xml:space="preserve">
+                <source>Manage forms</source>
+            </trans-unit>
+            <trans-unit id="formManager.create_new_form" xml:space="preserve">
+                <source>Create a new form</source>
+            </trans-unit>
+            <trans-unit id="formManager.edit_existing_forms" xml:space="preserve">
+                <source>Edit existing forms</source>
+            </trans-unit>
+            <trans-unit id="formManager.form_name" xml:space="preserve">
+                <source>Form name</source>
+            </trans-unit>
+            <trans-unit id="formManager.location" xml:space="preserve">
+                <source>Location</source>
+            </trans-unit>
+            <trans-unit id="formManager.references" xml:space="preserve">
+                <source>References</source>
+            </trans-unit>
+            <trans-unit id="formManager.options" xml:space="preserve">
+                <source>Options</source>
+            </trans-unit>
+            <trans-unit id="formManager.show_references" xml:space="preserve">
+                <source>Show references for this form</source>
+            </trans-unit>
+            <trans-unit id="formManager.edit_form" xml:space="preserve">
+                <source>Edit this form</source>
+            </trans-unit>
+            <trans-unit id="formManager.duplicate_this_form" xml:space="preserve">
+                <source>Duplicate this form</source>
+            </trans-unit>
+            <trans-unit id="formManager.delete_form" xml:space="preserve">
+                <source>Remove this form</source>
+            </trans-unit>
+            <trans-unit id="formManager.no_forms" xml:space="preserve">
+                <source>No form available.</source>
+            </trans-unit>
+            <trans-unit id="formManager.edit_form_not_allowed" xml:space="preserve">
+                <source>Edit this form is not allowed.</source>
+            </trans-unit>
+            <trans-unit id="formManager.delete_form_not_allowed" xml:space="preserve">
+                <source>Delete this form is not allowed.</source>
+            </trans-unit>
+            <trans-unit id="formManager.duplicate_identifier" xml:space="preserve">
+                <source>Duplicate identifier!</source>
+            </trans-unit>
+
+            <trans-unit id="formManager.selectablePrototypesConfiguration.standard.label" xml:space="preserve">
+                <source>Standard</source>
+            </trans-unit>
+            <trans-unit id="formManager.selectablePrototypesConfiguration.standard.newFormTemplates.blankForm.label" xml:space="preserve">
+                <source>Blank form</source>
+            </trans-unit>
+            <trans-unit id="formManager.selectablePrototypesConfiguration.standard.newFormTemplates.simpleContactForm.label" xml:space="preserve">
+                <source>Simple contact form (ext:form example)</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.header" xml:space="preserve">
+                <source>Form Editor</source>
+            </trans-unit>
+            <trans-unit id="formEditor.loading" xml:space="preserve">
+                <source>Loading...</source>
+            </trans-unit>
+            <trans-unit id="formEditor.spinner" xml:space="preserve">
+                <source>Loading...</source>
+            </trans-unit>
+            <trans-unit id="formEditor.save_button" xml:space="preserve">
+                <source>Save</source>
+            </trans-unit>
+            <trans-unit id="formEditor.undo_button" xml:space="preserve">
+                <source>Undo</source>
+            </trans-unit>
+            <trans-unit id="formEditor.redo_button" xml:space="preserve">
+                <source>Redo</source>
+            </trans-unit>
+            <trans-unit id="formEditor.new_page_button" xml:space="preserve">
+                <source>Create new page</source>
+            </trans-unit>
+            <trans-unit id="formEditor.structure" xml:space="preserve">
+                <source>Structure</source>
+            </trans-unit>
+            <trans-unit id="formEditor.insert_elements" xml:space="preserve">
+                <source>Insert elements</source>
+            </trans-unit>
+            <trans-unit id="formEditor.insert_pages" xml:space="preserve">
+                <source>Insert pages</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.formElementPropertyValidatorsDefinition.NotEmpty.label" xml:space="preserve">
+                <source>Required</source>
+            </trans-unit>
+            <trans-unit id="formEditor.formElementPropertyValidatorsDefinition.Integer.label" xml:space="preserve">
+                <source>Not a number</source>
+            </trans-unit>
+            <trans-unit id="formEditor.formElementPropertyValidatorsDefinition.NaiveEmail.label" xml:space="preserve">
+                <source>Invalid email address</source>
+            </trans-unit>
+            <trans-unit id="formEditor.formElementPropertyValidatorsDefinition.FormElementIdentifierWithinCurlyBraces.label" xml:space="preserve">
+                <source>Invalid form element</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.formElementGroups.input.label" xml:space="preserve">
+                <source>Basic elements</source>
+            </trans-unit>
+            <trans-unit id="formEditor.formElementGroups.select.label" xml:space="preserve">
+                <source>Select elements</source>
+            </trans-unit>
+            <trans-unit id="formEditor.formElementGroups.custom.label" xml:space="preserve">
+                <source>Advanced elements</source>
+            </trans-unit>
+            <trans-unit id="formEditor.formElementGroups.container.label" xml:space="preserve">
+                <source>Container elements</source>
+            </trans-unit>
+            <trans-unit id="formEditor.formElementGroups.page.label" xml:space="preserve">
+                <source>Page types</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.BaseFormElementMixin.editor.label.label" xml:space="preserve">
+                <source>Form name</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.Form.saveSuccessFlashMessageTitle" xml:space="preserve">
+                <source>Save</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.saveSuccessFlashMessageMessage" xml:space="preserve">
+                <source>The form has been successfully saved.</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.modals.validationErrors.dialogTitle" xml:space="preserve">
+                <source>Alert</source>
+            </trans-unit>
+            <trans-unit id="formEditor.modals.validationErrors.dialogMessage" xml:space="preserve">
+                <source>Some elements are not configured properly. Please check the following elements:</source>
+            </trans-unit>
+            <trans-unit id="formEditor.modals.validationErrors.confirmButton" xml:space="preserve">
+                <source>OK</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.modals.insertElements.dialogTitle" xml:space="preserve">
+                <source>New element</source>
+            </trans-unit>
+            <trans-unit id="formEditor.modals.newPages.dialogTitle" xml:space="preserve">
+                <source>New page</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.modals.removeElement.dialogTitle" xml:space="preserve">
+                <source>Remove element?</source>
+            </trans-unit>
+            <trans-unit id="formEditor.modals.removeElement.dialogMessage" xml:space="preserve">
+                <source>Are you sure that you want to remove this element?</source>
+            </trans-unit>
+            <trans-unit id="formEditor.modals.removeElement.confirmButton" xml:space="preserve">
+                <source>Remove</source>
+            </trans-unit>
+            <trans-unit id="formEditor.modals.removeElement.cancleButton" xml:space="preserve">
+                <source>Cancel</source>
+            </trans-unit>
+            <trans-unit id="formEditor.modals.removeElement.lastAvailablePageFlashMessageTitle" xml:space="preserve">
+                <source>Error</source>
+            </trans-unit>
+            <trans-unit id="formEditor.modals.removeElement.lastAvailablePageFlashMessageMessage" xml:space="preserve">
+                <source>There must be at least one page within your form.</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.modals.close.dialogMessage" xml:space="preserve">
+                <source>You have currently unsaved changes. Are you sure that you want to discard all changes?</source>
+            </trans-unit>
+            <trans-unit id="formEditor.modals.close.dialogTitle" xml:space="preserve">
+                <source>Do you want to quit without saving?</source>
+            </trans-unit>
+            <trans-unit id="formEditor.modals.close.confirmButton" xml:space="preserve">
+                <source>Yes, discard my changes</source>
+            </trans-unit>
+            <trans-unit id="formEditor.modals.close.cancleButton" xml:space="preserve">
+                <source>No, I will continue editing</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.pagination.title" xml:space="preserve">
+                <source>Page {0} of {1}</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.MinimumMaximumEditorsMixin.editor.minimum.label" xml:space="preserve">
+                <source>Minimum</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.MinimumMaximumEditorsMixin.editor.maximum.label" xml:space="preserve">
+                <source>Maximum</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.TextMixin.editor.placeholder.label" xml:space="preserve">
+                <source>Placeholder</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.editor.defaultValue.label" xml:space="preserve">
+                <source>Default value</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.editor.validators.label" xml:space="preserve">
+                <source>Validators</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.editor.validators.EmptyValue.label" xml:space="preserve">
+                <source>Add validator</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.editor.validators.Alphanumeric.label" xml:space="preserve">
+                <source>Alphanumeric</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.editor.validators.Text.label" xml:space="preserve">
+                <source>Non-XML text</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.editor.validators.StringLength.label" xml:space="preserve">
+                <source>String length</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.editor.validators.EmailAddress.label" xml:space="preserve">
+                <source>Email</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.editor.validators.Integer.label" xml:space="preserve">
+                <source>Integer number</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.editor.validators.Float.label" xml:space="preserve">
+                <source>Floating-point number</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.editor.validators.NumberRange.label" xml:space="preserve">
+                <source>Number range</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.editor.validators.RegularExpression.label" xml:space="preserve">
+                <source>Regular expression</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.validators.Alphanumeric.editor.header.label" xml:space="preserve">
+                <source>Alphanumeric</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.validators.Text.editor.header.label" xml:space="preserve">
+                <source>Non-XML text</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.validators.StringLength.editor.header.label" xml:space="preserve">
+                <source>String length</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.validators.EmailAddress.editor.header.label" xml:space="preserve">
+                <source>Email</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.validators.Integer.editor.header.label" xml:space="preserve">
+                <source>Integer number</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.validators.Float.editor.header.label" xml:space="preserve">
+                <source>Floating-point number</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.validators.NumberRange.editor.header.label" xml:space="preserve">
+                <source>Number range</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.validators.RegularExpression.editor.header.label" xml:space="preserve">
+                <source>Regular expression</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.validators.RegularExpression.editor.regex.label" xml:space="preserve">
+                <source>Regular expression</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.TextMixin.validators.RegularExpression.editor.regex.fieldExplanationText" xml:space="preserve">
+                <source>Enter a valid PHP PCRE regular expression here.</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.SelectionMixin.editor.options.label" xml:space="preserve">
+                <source>Choices</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.SelectionMixin.editor.options.removeLastAvailableRowFlashMessageTitle" xml:space="preserve">
+                <source>Error</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.SelectionMixin.editor.options.removeLastAvailableRowFlashMessageMessage" xml:space="preserve">
+                <source>There must be at least one row within your options.</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.MultiSelectionMixin.editor.validators.label" xml:space="preserve">
+                <source>Validators</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.MultiSelectionMixin.editor.validators.EmptyValue.label" xml:space="preserve">
+                <source>Add validator</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.MultiSelectionMixin.editor.validators.Count.label" xml:space="preserve">
+                <source>Number of submitted values</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.MultiSelectionMixin.validators.Count.editor.header.label" xml:space="preserve">
+                <source>Number of submitted values</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.FileUploadMixin.editor.saveToFileMount.label" xml:space="preserve">
+                <source>Uploads save path</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.Form.editor.submitButtonLabel.label" xml:space="preserve">
+                <source>Submit label</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.editor.finishers.label" xml:space="preserve">
+                <source>Finishers</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.editor.finishers.EmptyValue.label" xml:space="preserve">
+                <source>Add finisher</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.editor.finishers.EmailToSender.label" xml:space="preserve">
+                <source>Email to sender</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.editor.finishers.EmailToReceiver.label" xml:space="preserve">
+                <source>Email to receiver</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.editor.finishers.Redirect.label" xml:space="preserve">
+                <source>Redirect to a page</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.editor.finishers.DeleteUploads.label" xml:space="preserve">
+                <source>Delete uploads</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToSender.editor.header.label" xml:space="preserve">
+                <source>Send email (sender)</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToSender.editor.subject.label" xml:space="preserve">
+                <source>Subject</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToSender.editor.recipientAddress.label" xml:space="preserve">
+                <source>Recipient address</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToSender.editor.recipientName.label" xml:space="preserve">
+                <source>Recipient name</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToSender.editor.senderAddress.label" xml:space="preserve">
+                <source>Sender address</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToSender.editor.senderName.label" xml:space="preserve">
+                <source>Sender name</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToSender.editor.replyToAddress.label" xml:space="preserve">
+                <source>Reply-to address</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToSender.editor.carbonCopyAddress.label" xml:space="preserve">
+                <source>CC address</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToSender.editor.blindCarbonCopyAddress.label" xml:space="preserve">
+                <source>BCC address</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToSender.editor.format.label" xml:space="preserve">
+                <source>Format</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToSender.editor.format.1" xml:space="preserve">
+                <source>Plain text</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToSender.editor.format.2" xml:space="preserve">
+                <source>HTML</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToSender.editor.attachUploads.label" xml:space="preserve">
+                <source>Attach uploads</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.header.label" xml:space="preserve">
+                <source>Send email (receiver)</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.subject.label" xml:space="preserve">
+                <source>Subject</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.recipientAddress.label" xml:space="preserve">
+                <source>Recipient address</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.recipientName.label" xml:space="preserve">
+                <source>Recipient name</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.senderAddress.label" xml:space="preserve">
+                <source>Sender address</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.senderName.label" xml:space="preserve">
+                <source>Sender name</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.replyToAddress.label" xml:space="preserve">
+                <source>Reply-to address</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.carbonCopyAddress.label" xml:space="preserve">
+                <source>CC address</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.blindCarbonCopyAddress.label" xml:space="preserve">
+                <source>BCC address</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.format.label" xml:space="preserve">
+                <source>Format</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.format.1" xml:space="preserve">
+                <source>Plain text</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.format.2" xml:space="preserve">
+                <source>HTML</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.attachUploads.label" xml:space="preserve">
+                <source>Attach uploads</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.language.label" xml:space="preserve">
+                <source>Translation language</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.EmailToReceiver.editor.language.1" xml:space="preserve">
+                <source>EN</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.Form.finisher.Redirect.editor.header.label" xml:space="preserve">
+                <source>Redirect to a page</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.Redirect.editor.pageUid.label" xml:space="preserve">
+                <source>Page</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.Redirect.editor.pageUid.buttonLabel" xml:space="preserve">
+                <source>Pages</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.Redirect.editor.additionalParameters.label" xml:space="preserve">
+                <source>Additional parameters</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.Form.finisher.DeleteUploads.editor.header.label" xml:space="preserve">
+                <source>Delete uploads</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.Confirmation.editor.header.label" xml:space="preserve">
+                <source>Confirmation message</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.Closure.editor.header.label" xml:space="preserve">
+                <source>Execute a closure</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.FlashMessage.editor.header.label" xml:space="preserve">
+                <source>Flash message</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Form.finisher.SaveToDatabase.editor.header.label" xml:space="preserve">
+                <source>Save the mail to the Database</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.ReadOnlyFormElement.editor.label.label" xml:space="preserve">
+                <source>Element name</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.FormElement.editor.label.label" xml:space="preserve">
+                <source>Element name</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.FormElement.editor.requiredValidator.label" xml:space="preserve">
+                <source>Required field</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.Page.label" xml:space="preserve">
+                <source>Page</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Page.editor.label.label" xml:space="preserve">
+                <source>Page name</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Page.editor.previousButtonLabel.label" xml:space="preserve">
+                <source>Previous label</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Page.editor.nextButtonLabel.label" xml:space="preserve">
+                <source>Next label</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.SummaryPage.label" xml:space="preserve">
+                <source>Summary page</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.SummaryPage.editor.label.label" xml:space="preserve">
+                <source>Page name</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.Fieldset.label" xml:space="preserve">
+                <source>Fieldset</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.Fieldset.editor.label.label" xml:space="preserve">
+                <source>Fieldset name</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.Text.label" xml:space="preserve">
+                <source>Text</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.Password.label" xml:space="preserve">
+                <source>Password</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.AdvancedPassword.label" xml:space="preserve">
+                <source>Advanced password</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.AdvancedPassword.editor.confirmationLabel.label" xml:space="preserve">
+                <source>Confirmation label</source>
+            </trans-unit>
+            <trans-unit id="formEditor.element.AdvancedPassword.editor.confirmationLabel.predefinedDefaults" xml:space="preserve">
+                <source>Confirmation</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.Textarea.label" xml:space="preserve">
+                <source>Textarea</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.Checkbox.label" xml:space="preserve">
+                <source>Checkbox</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.MultiCheckbox.label" xml:space="preserve">
+                <source>Multi checkbox</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.MultiSelect.label" xml:space="preserve">
+                <source>Multi select</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.RadioButton.label" xml:space="preserve">
+                <source>Radio button</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.SingleSelect.label" xml:space="preserve">
+                <source>Single select</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.DatePicker.label" xml:space="preserve">
+                <source>Date picker</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.DatePicker.editor.validators.label" xml:space="preserve">
+                <source>Validators</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.DatePicker.editor.validators.EmptyValue.label" xml:space="preserve">
+                <source>Add validator</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.DatePicker.editor.validators.DateTime.label" xml:space="preserve">
+                <source>Date/time</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.DatePicker.validators.DateTime.editor.header.label" xml:space="preserve">
+                <source>Date/time</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.StaticText.label" xml:space="preserve">
+                <source>Static text</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.StaticText.editor.staticText.label" xml:space="preserve">
+                <source>Text</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.ContentElement.label" xml:space="preserve">
+                <source>Content element</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.ContentElement.selectContentElement" xml:space="preserve">
+                <source>No content element selected</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.StaticText.editor.contentElement.label" xml:space="preserve">
+                <source>Content element uid</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.StaticText.editor.contentElement.buttonLabel" xml:space="preserve">
+                <source>tt_content</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.FileUpload.label" xml:space="preserve">
+                <source>File upload</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.FileUpload.editor.allowedMimeTypes.label" xml:space="preserve">
+                <source>Allowed file mime types</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.FileUpload.editor.allowedMimeTypes.1" xml:space="preserve">
+                <source>Documents (doc, docx, odt, pdf)</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.FileUpload.editor.allowedMimeTypes.2" xml:space="preserve">
+                <source>Spreadsheet documents (xls)</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.ImageUpload.label" xml:space="preserve">
+                <source>Image upload</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.elements.UnknownElement" xml:space="preserve">
+                <source>Unknown Element</source>
+            </trans-unit>
+
+            <trans-unit id="formEditor.stage.toolbar.new_element" xml:space="preserve">
+                <source>Create new element</source>
+            </trans-unit>
+            <trans-unit id="formEditor.stage.toolbar.remove" xml:space="preserve">
+                <source>Remove</source>
+            </trans-unit>
+            <trans-unit id="formEditor.stage.toolbar.new_element.inside" xml:space="preserve">
+                <source>Inside</source>
+            </trans-unit>
+            <trans-unit id="formEditor.stage.toolbar.new_element.after" xml:space="preserve">
+                <source>After</source>
+            </trans-unit>
+        </body>
+    </file>
 </xliff>
diff --git a/typo3/sysext/form/Resources/Private/Language/locallang.xlf b/typo3/sysext/form/Resources/Private/Language/locallang.xlf
index cb38da6f0ce7559c2d83e6ab1c2f86f6ac4373e1..f7fe933149838797d05475f1caff9e6d2c4b5014 100644
--- a/typo3/sysext/form/Resources/Private/Language/locallang.xlf
+++ b/typo3/sysext/form/Resources/Private/Language/locallang.xlf
@@ -1,209 +1,96 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <xliff version="1.0" xmlns:t3="http://typo3.org/schemas/xliff">
-	<file t3:id="1415814824" source-language="en" datatype="plaintext" original="messages" date="2011-10-17T20:22:32Z" product-name="form">
-		<header/>
-		<body>
-			<trans-unit id="tx_form_domain_model_element_button.value">
-				<source>Push this button</source>
-			</trans-unit>
-			<trans-unit id="tx_form_domain_model_element_submit.value">
-				<source>Submit form</source>
-			</trans-unit>
-			<trans-unit id="tx_form_domain_model_element_reset.value">
-				<source>Clear form</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_alphabetic.message">
-				<source>Use alphabetic characters</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_alphabetic.message2">
-				<source>whitespace allowed</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_alphabetic.error">
-				<source>The value contains not only alphabetic characters</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_alphanumeric.message">
-				<source>Use alphanumeric characters</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_alphanumeric.message2">
-				<source>whitespace allowed</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_alphanumeric.error">
-				<source>The value contains not only alphanumeric characters</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_between.message">
-				<source>The value must be between %minimum and %maximum</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_between.message2">
-				<source>inclusively</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_between.error">
-				<source>The value is not between %minimum and %maximum</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_between.error2">
-				<source>inclusively</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.message">
-				<source>(%format)</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.strftime.A">
-				<source>dddd</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.strftime.a">
-				<source>ddd</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.strftime.d">
-				<source>dd</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.strftime.e">
-				<source>d</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.strftime.B">
-				<source>mmmm</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.strftime.b">
-				<source>mmm</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.strftime.m">
-				<source>mm</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.strftime.Y">
-				<source>yyyy</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.strftime.y">
-				<source>yy</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.strftime.H">
-				<source>HH</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.strftime.I">
-				<source>hh</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.strftime.M">
-				<source>mm</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.strftime.S">
-				<source>ss</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_date.error">
-				<source>The value does not appear to be a valid date</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_digit.message">
-				<source>Use digit characters</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_digit.error">
-				<source>The value contains not only digit characters</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_email.message">
-				<source>(john.doe@domain.com)</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_email.error">
-				<source>This is not a valid email address</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_equals.message">
-				<source>This field must be equal to '%field'</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_equals.error">
-				<source>The value does not equal the value in field '%field'</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_fileallowedtypes.message">
-				<source>(%allowedTypes)</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_fileallowedtypes.error">
-				<source>The file type is not allowed</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_filemaximumsize.message">
-				<source>The filesize must be smaller than %maximum</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_filemaximumsize.error">
-				<source>The filesize is too big</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_fileminimumsize.message">
-				<source>The filesize must be bigger than %minimum</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_fileminimumsize.error">
-				<source>The filesize is too small</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_float.message">
-				<source>Enter a float</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_float.error">
-				<source>The value does not appear to be a float</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_greaterthan.message">
-				<source>The value must be greater than %minimum</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_greaterthan.error">
-				<source>The value does not appear to be greater than %minimum</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_inarray.message">
-				<source>Only a few values are possible</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_inarray.error">
-				<source>The value does not appear to be valid</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_integer.message">
-				<source>Use an integer</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_integer.error">
-				<source>The value does not appear to be an integer</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_ip.message">
-				<source>(123.123.123.123)</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_ip.error">
-				<source>The value does not appear to be a valid IP address</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_length.message">
-				<source>The length of the value must have a minimum of %minimum characters</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_length.message2">
-				<source>and a maximum of %maximum</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_length.error">
-				<source>The value is less than %minimum characters long</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_length.error2">
-				<source>or longer than %maximum</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_lessthan.message">
-				<source>The value must be less than %maximum</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_lessthan.error">
-				<source>The value does not appear to be less than %maximum</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_regexp.message">
-				<source>Use the right pattern</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_regexp.error">
-				<source>The value does not match against pattern</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_required.message">
-				<source>Required</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_required.error">
-				<source>This field is required</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_uri.message">
-				<source>The value must be a URI</source>
-			</trans-unit>
-			<trans-unit id="tx_form_system_validate_uri.error">
-				<source>The value does not appear to be a URI</source>
-			</trans-unit>
-			<trans-unit id="tx_form_view_confirmation.message">
-				<source>Please check your input and confirm by using the appropriate button</source>
-			</trans-unit>
-			<trans-unit id="tx_form_view_confirmation.confirm">
-				<source>Confirm</source>
-			</trans-unit>
-			<trans-unit id="tx_form_view_confirmation.donotconfirm">
-				<source>Go back to the form</source>
-			</trans-unit>
-			<trans-unit id="tx_form_view_mail.success">
-				<source>The form has been sent successfully by mail</source>
-			</trans-unit>
-			<trans-unit id="tx_form_view_mail.error">
-				<source>There was an error when sending the form by mail</source>
-			</trans-unit>
-		</body>
-	</file>
+    <file t3:id="1475977066" source-language="en" datatype="plaintext" original="messages" date="2016-10-09T03:38:32Z" product-name="form">
+        <header/>
+        <body>
+            <trans-unit id="element.Form.renderingOptions.submitButtonLabel" xml:space="preserve">
+                <source>Submit</source>
+            </trans-unit>
+            <trans-unit id="element.Page.renderingOptions.previousButtonLabel" xml:space="preserve">
+                <source>previous Page</source>
+            </trans-unit>
+            <trans-unit id="element.Page.renderingOptions.nextButtonLabel" xml:space="preserve">
+                <source>next Page</source>
+            </trans-unit>
+            <trans-unit id="element.SummaryPage.renderingOptions.previousButtonLabel" xml:space="preserve">
+                <source>previous Page</source>
+            </trans-unit>
+            <trans-unit id="element.SummaryPage.renderingOptions.nextButtonLabel" xml:space="preserve">
+                <source>next Page</source>
+            </trans-unit>
+            <trans-unit id="element.ImageUpload.properties.SummaryPage.altText" xml:space="preserve">
+                <source>uploaded image</source>
+            </trans-unit>
+
+            <trans-unit id="validation.error.1221560910" xml:space="preserve">
+                <source>This field is mandatory</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1221560718" xml:space="preserve">
+                <source>This field is mandatory</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1347992400" xml:space="preserve">
+                <source>This field is mandatory</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1347992453" xml:space="preserve">
+                <source>This field is mandatory</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1238087674" xml:space="preserve">
+                <source>Please enter a valid Date</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1221551320" xml:space="preserve">
+                <source>Please enter letters or digits</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1221565786" xml:space="preserve">
+                <source>Please enter a valid text (e.g. without XML tags)</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1238110957" xml:space="preserve">
+                <source>Please enter a valid text</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1269883975" xml:space="preserve">
+                <source>Please enter a valid text</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1428504122" xml:space="preserve">
+                <source>Please enter a text between %s and %s characters</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1238108068" xml:space="preserve">
+                <source>Please enter a text which is longer than %s characters</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1238108069" xml:space="preserve">
+                <source>Please enter a text which is not longer than %s characters</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1221559976" xml:space="preserve">
+                <source>Please enter a valid email address</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1221560494" xml:space="preserve">
+                <source>Please enter a valid number</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1221560288" xml:space="preserve">
+                <source>Please enter a valid floating point number</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1221563685" xml:space="preserve">
+                <source>Please enter a valid number</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1221561046" xml:space="preserve">
+                <source>Please enter a valid number between %s and %s</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1221565130" xml:space="preserve">
+                <source>Please enter a valid value</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1475002976" xml:space="preserve">
+                <source>The given subject is not countable.</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1475002994" xml:space="preserve">
+                <source>Please enter a valid number between %s and %s</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1471708997" xml:space="preserve">
+                <source>The given value was not an instance of \TYPO3\CMS\Extbase\Domain\Model\FileReference or \TYPO3\CMS\Core\Resource\File.</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1471708998" xml:space="preserve">
+                <source>The media type "%s" is not allowed for this file.</source>
+            </trans-unit>
+            <trans-unit id="validation.error.1476396435" xml:space="preserve">
+                <source>Do not fill this field</source>
+            </trans-unit>
+        </body>
+    </file>
 </xliff>
diff --git a/typo3/sysext/form/Resources/Private/Language/locallang_formManager_javascript.xlf b/typo3/sysext/form/Resources/Private/Language/locallang_formManager_javascript.xlf
new file mode 100644
index 0000000000000000000000000000000000000000..1468bc84c8c6680368f2316ad01d9a2b57e11669
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Language/locallang_formManager_javascript.xlf
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xliff version="1.0" xmlns:t3="http://typo3.org/schemas/xliff">
+    <file t3:id="1477653834" source-language="en" datatype="plaintext" original="messages" date="2016-10-09T03:38:32Z" product-name="form">
+        <header/>
+        <body>
+            <trans-unit id="formManager.form_name" xml:space="preserve">
+                <source>Form name</source>
+            </trans-unit>
+            <trans-unit id="formManager.new_form_name" xml:space="preserve">
+                <source>New form name</source>
+            </trans-unit>
+            <trans-unit id="formManager.form_save_path" xml:space="preserve">
+                <source>Form storage</source>
+            </trans-unit>
+            <trans-unit id="formManager.form_prototype" xml:space="preserve">
+                <source>Form prototype</source>
+            </trans-unit>
+            <trans-unit id="formManager.form_template" xml:space="preserve">
+                <source>Start template</source>
+            </trans-unit>
+            <trans-unit id="formManager.cancel" xml:space="preserve">
+                <source>Cancel</source>
+            </trans-unit>
+            <trans-unit id="formManager.remove_form" xml:space="preserve">
+                <source>Remove</source>
+            </trans-unit>
+            <trans-unit id="formManager.remove_form_title" xml:space="preserve">
+                <source>Remove form</source>
+            </trans-unit>
+            <trans-unit id="formManager.remove_form_message" xml:space="preserve">
+                <source>Are you sure that you want to remove this form?</source>
+            </trans-unit>
+            <trans-unit id="formManager.newFormWizard.step1.title" xml:space="preserve">
+                <source>Create new form</source>
+            </trans-unit>
+            <trans-unit id="formManager.newFormWizard.step1.advanced" xml:space="preserve">
+                <source>Advanced settings</source>
+            </trans-unit>
+            <trans-unit id="formManager.newFormWizard.step2.title" xml:space="preserve">
+                <source>Advanced settings</source>
+            </trans-unit>
+            <trans-unit id="formManager.newFormWizard.step3.title" xml:space="preserve">
+                <source>Ready</source>
+            </trans-unit>
+            <trans-unit id="formManager.newFormWizard.step3.message" xml:space="preserve">
+                <source>Now you are ready to create your new form.</source>
+            </trans-unit>
+            <trans-unit id="formManager.duplicateFormWizard.step1.title" xml:space="preserve">
+                <source>Duplicate form "{0}"</source>
+            </trans-unit>
+            <trans-unit id="formManager.no_references" xml:space="preserve">
+                <source>There are no references yet</source>
+            </trans-unit>
+            <trans-unit id="formManager.page" xml:space="preserve">
+                <source>Page</source>
+            </trans-unit>
+            <trans-unit id="formManager.record" xml:space="preserve">
+                <source>Record</source>
+            </trans-unit>
+            <trans-unit id="formManager.references.title" xml:space="preserve">
+                <source>References</source>
+            </trans-unit>
+            <trans-unit id="formManager.references.headline" xml:space="preserve">
+                <source>References for "{0}"</source>
+            </trans-unit>
+        </body>
+    </file>
+</xliff>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Language/locallang_module.xlf b/typo3/sysext/form/Resources/Private/Language/locallang_module.xlf
new file mode 100644
index 0000000000000000000000000000000000000000..fd1de2ed0b3c677fb50f8a741f39faa8531ed077
--- /dev/null
+++ b/typo3/sysext/form/Resources/Private/Language/locallang_module.xlf
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xliff version="1.0" xmlns:t3="http://typo3.org/schemas/xliff">
+    <file t3:id="1465049996" source-language="en" datatype="plaintext" original="messages" date="2016-06-04T20:22:33Z" product-name="form">
+        <header/>
+        <body>
+            <trans-unit id="mlang_labels_tablabel">
+                <source>Build custom forms</source>
+            </trans-unit>
+            <trans-unit id="mlang_labels_tabdescr">
+                <source>Build custom forms. TODO: Add more description.</source>
+            </trans-unit>
+            <trans-unit id="mlang_tabs_tab">
+                <source>Forms</source>
+            </trans-unit>
+        </body>
+    </file>
+</xliff>
diff --git a/typo3/sysext/form/Resources/Private/Language/locallang_wizard.xlf b/typo3/sysext/form/Resources/Private/Language/locallang_wizard.xlf
deleted file mode 100644
index 47ec19b828be86c6cc03e1ad1b0c8f80af98e41c..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Language/locallang_wizard.xlf
+++ /dev/null
@@ -1,875 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xliff version="1.0" xmlns:t3="http://typo3.org/schemas/xliff">
-	<file t3:id="1415814825" source-language="en" datatype="plaintext" original="messages" date="2011-10-17T20:22:33Z" product-name="form">
-		<header/>
-		<body>
-			<trans-unit id="title">
-				<source>Form Wizard</source>
-			</trans-unit>
-			<trans-unit id="yes">
-				<source>Yes</source>
-			</trans-unit>
-			<trans-unit id="no">
-				<source>No</source>
-			</trans-unit>
-			<trans-unit id="refresh">
-				<source>Refresh without saving</source>
-			</trans-unit>
-			<trans-unit id="errorTitle">
-				<source>Wizard error</source>
-			</trans-unit>
-			<trans-unit id="errorMessage">
-				<source>No reference to record</source>
-			</trans-unit>
-			<trans-unit id="save">
-				<source>Save form</source>
-			</trans-unit>
-			<trans-unit id="saveAndClose">
-				<source>Save and close form</source>
-			</trans-unit>
-			<trans-unit id="history_undo">
-				<source>Undo</source>
-			</trans-unit>
-			<trans-unit id="history_redo">
-				<source>Redo</source>
-			</trans-unit>
-			<trans-unit id="action_save">
-				<source>Saving form</source>
-			</trans-unit>
-			<trans-unit id="action_save_error">
-				<source>Server-side failure with status code</source>
-			</trans-unit>
-			<trans-unit id="action_save_message_failed">
-				<source>Failed to save the form</source>
-			</trans-unit>
-			<trans-unit id="action_save_message_saved">
-				<source>Changes saved successfully</source>
-			</trans-unit>
-			<trans-unit id="button_remove">
-				<source>Remove</source>
-			</trans-unit>
-			<trans-unit id="left_elements">
-				<source>Elements</source>
-			</trans-unit>
-			<trans-unit id="left_elements_intro_title">
-				<source>Adding elements to the form</source>
-			</trans-unit>
-			<trans-unit id="left_elements_intro_description">
-				<source>Drag or double-click elements to add</source>
-			</trans-unit>
-			<trans-unit id="left_elements_basic">
-				<source>Basic form elements</source>
-			</trans-unit>
-			<trans-unit id="basic_button">
-				<source>Button</source>
-			</trans-unit>
-			<trans-unit id="basic_checkbox">
-				<source>Checkbox</source>
-			</trans-unit>
-			<trans-unit id="basic_fieldset">
-				<source>Fieldset</source>
-			</trans-unit>
-			<trans-unit id="basic_fileupload">
-				<source>Upload Field</source>
-			</trans-unit>
-			<trans-unit id="basic_hidden">
-				<source>Hidden Field</source>
-			</trans-unit>
-			<trans-unit id="basic_input">
-				<source>Input Field</source>
-			</trans-unit>
-			<trans-unit id="basic_password">
-				<source>Password Field</source>
-			</trans-unit>
-			<trans-unit id="basic_radio">
-				<source>Radio Button</source>
-			</trans-unit>
-			<trans-unit id="basic_reset">
-				<source>Reset Button</source>
-			</trans-unit>
-			<trans-unit id="basic_select">
-				<source>Drop Down</source>
-			</trans-unit>
-			<trans-unit id="basic_submit">
-				<source>Submit Button</source>
-			</trans-unit>
-			<trans-unit id="basic_textarea">
-				<source>Text Area</source>
-			</trans-unit>
-			<trans-unit id="basic_textline">
-				<source>Text Field</source>
-			</trans-unit>
-			<trans-unit id="left_elements_content">
-				<source>Content elements</source>
-			</trans-unit>
-			<trans-unit id="content_header">
-				<source>Header</source>
-			</trans-unit>
-			<trans-unit id="content_textblock">
-				<source>Text block</source>
-			</trans-unit>
-			<trans-unit id="left_elements_predefined">
-				<source>Predefined form elements</source>
-			</trans-unit>
-			<trans-unit id="predefined_email">
-				<source>Email</source>
-			</trans-unit>
-			<trans-unit id="predefined_radiogroup">
-				<source>Radio Button Group</source>
-			</trans-unit>
-			<trans-unit id="predefined_checkboxgroup">
-				<source>Checkbox Group</source>
-			</trans-unit>
-			<trans-unit id="predefined_name">
-				<source>Full Name</source>
-			</trans-unit>
-			<trans-unit id="left_options">
-				<source>Options</source>
-			</trans-unit>
-			<trans-unit id="options_error">
-				<source>Error</source>
-			</trans-unit>
-			<trans-unit id="options_error_message">
-				<source>There is an error in the settings of the current element. Please check!</source>
-			</trans-unit>
-			<trans-unit id="options_dummy_title">
-				<source>Please select an element on the right</source>
-			</trans-unit>
-			<trans-unit id="options_dummy_description">
-				<source>When an element has been selected, this area will show the options for the selected element</source>
-			</trans-unit>
-			<trans-unit id="options_attributes">
-				<source>Attributes Properties</source>
-			</trans-unit>
-			<trans-unit id="attributes_accept">
-				<source>Accept</source>
-			</trans-unit>
-			<trans-unit id="attributes_acceptcharset">
-				<source>Acceptcharset</source>
-			</trans-unit>
-			<trans-unit id="attributes_accesskey">
-				<source>Accesskey</source>
-			</trans-unit>
-			<trans-unit id="attributes_action">
-				<source>Action</source>
-			</trans-unit>
-			<trans-unit id="attributes_alt">
-				<source>Alt</source>
-			</trans-unit>
-			<trans-unit id="attributes_autocomplete">
-				<source>Autocomplete</source>
-			</trans-unit>
-			<trans-unit id="attributes_autocomplete_none">
-				<source>Not set</source>
-			</trans-unit>
-			<trans-unit id="attributes_autocomplete_off">
-				<source>Off</source>
-			</trans-unit>
-			<trans-unit id="attributes_autocomplete_on">
-				<source>On</source>
-			</trans-unit>
-			<trans-unit id="attributes_autofocus">
-				<source>Autofocus</source>
-			</trans-unit>
-			<trans-unit id="attributes_checked">
-				<source>Checked</source>
-			</trans-unit>
-			<trans-unit id="attributes_class">
-				<source>Class</source>
-			</trans-unit>
-			<trans-unit id="attributes_cols">
-				<source>Cols</source>
-			</trans-unit>
-			<trans-unit id="attributes_contenteditable">
-				<source>Content editable</source>
-			</trans-unit>
-			<trans-unit id="attributes_contenteditable_none">
-				<source>Not set</source>
-			</trans-unit>
-			<trans-unit id="attributes_contenteditable_true">
-				<source>True</source>
-			</trans-unit>
-			<trans-unit id="attributes_contenteditable_false">
-				<source>False</source>
-			</trans-unit>
-			<trans-unit id="attributes_contextmenu">
-				<source>Contextmenu</source>
-			</trans-unit>
-			<trans-unit id="attributes_dir">
-				<source>Dir</source>
-			</trans-unit>
-			<trans-unit id="attributes_dir_ltr">
-				<source>Left to right</source>
-			</trans-unit>
-			<trans-unit id="attributes_dir_rtl">
-				<source>Right to left</source>
-			</trans-unit>
-			<trans-unit id="attributes_disabled">
-				<source>Disabled</source>
-			</trans-unit>
-			<trans-unit id="attributes_draggable">
-				<source>Draggable</source>
-			</trans-unit>
-			<trans-unit id="attributes_draggable_none">
-				<source>Not set</source>
-			</trans-unit>
-			<trans-unit id="attributes_draggable_true">
-				<source>True</source>
-			</trans-unit>
-			<trans-unit id="attributes_draggable_false">
-				<source>False</source>
-			</trans-unit>
-			<trans-unit id="attributes_draggable_auto">
-				<source>Auto</source>
-			</trans-unit>
-			<trans-unit id="attributes_dropzone">
-				<source>Dropzone</source>
-			</trans-unit>
-			<trans-unit id="attributes_enctype">
-				<source>Enctype</source>
-			</trans-unit>
-			<trans-unit id="attributes_enctype_1">
-				<source>Encoded</source>
-			</trans-unit>
-			<trans-unit id="attributes_enctype_2">
-				<source>No encoding - File upload</source>
-			</trans-unit>
-			<trans-unit id="attributes_enctype_3">
-				<source>No encoding - Spaces converted</source>
-			</trans-unit>
-			<trans-unit id="attributes_hidden">
-				<source>Hidden</source>
-			</trans-unit>
-			<trans-unit id="attributes_height">
-				<source>Height</source>
-			</trans-unit>
-			<trans-unit id="attributes_id">
-				<source>Id</source>
-			</trans-unit>
-			<trans-unit id="attributes_inputmode">
-				<source>Inputmode</source>
-			</trans-unit>
-			<trans-unit id="attributes_inputmode_none">
-				<source>Not set</source>
-			</trans-unit>
-			<trans-unit id="attributes_inputmode_verbatim">
-				<source>Verbatim</source>
-			</trans-unit>
-			<trans-unit id="attributes_inputmode_latin">
-				<source>Latin</source>
-			</trans-unit>
-			<trans-unit id="attributes_inputmode_latin-name">
-				<source>Latin-name</source>
-			</trans-unit>
-			<trans-unit id="attributes_inputmode_latin-prose">
-				<source>Latin-prose</source>
-			</trans-unit>
-			<trans-unit id="attributes_inputmode_full-width-latin">
-				<source>Full-width-latin</source>
-			</trans-unit>
-			<trans-unit id="attributes_inputmode_kana">
-				<source>Kana</source>
-			</trans-unit>
-			<trans-unit id="attributes_inputmode_kana-name">
-				<source>Kana-name</source>
-			</trans-unit>
-			<trans-unit id="attributes_inputmode_katakana">
-				<source>Katakana</source>
-			</trans-unit>
-			<trans-unit id="attributes_inputmode_numeric">
-				<source>Numeric</source>
-			</trans-unit>
-			<trans-unit id="attributes_inputmode_tel">
-				<source>Tel</source>
-			</trans-unit>
-			<trans-unit id="attributes_inputmode_email">
-				<source>Email</source>
-			</trans-unit>
-			<trans-unit id="attributes_inputmode_url">
-				<source>Url</source>
-			</trans-unit>
-			<trans-unit id="attributes_label">
-				<source>Label</source>
-			</trans-unit>
-			<trans-unit id="attributes_lang">
-				<source>Lang</source>
-			</trans-unit>
-			<trans-unit id="attributes_list">
-				<source>List</source>
-			</trans-unit>
-			<trans-unit id="attributes_max">
-				<source>Max</source>
-			</trans-unit>
-			<trans-unit id="attributes_maxlength">
-				<source>Maxlength</source>
-			</trans-unit>
-			<trans-unit id="attributes_method">
-				<source>Method</source>
-			</trans-unit>
-			<trans-unit id="attributes_min">
-				<source>Min</source>
-			</trans-unit>
-			<trans-unit id="attributes_minlength">
-				<source>Minlength</source>
-			</trans-unit>
-			<trans-unit id="attributes_method_get">
-				<source>Get</source>
-			</trans-unit>
-			<trans-unit id="attributes_pattern">
-				<source>Pattern</source>
-			</trans-unit>
-			<trans-unit id="attributes_method_post">
-				<source>Post</source>
-			</trans-unit>
-			<trans-unit id="attributes_multiple">
-				<source>Multiple</source>
-			</trans-unit>
-			<trans-unit id="attributes_name">
-				<source>Name</source>
-			</trans-unit>
-			<trans-unit id="attributes_novalidate">
-				<source>Novalidate</source>
-			</trans-unit>
-			<trans-unit id="attributes_placeholder">
-				<source>Placeholder</source>
-			</trans-unit>
-			<trans-unit id="attributes_readonly">
-				<source>Readonly</source>
-			</trans-unit>
-			<trans-unit id="attributes_required">
-				<source>Required</source>
-			</trans-unit>
-			<trans-unit id="attributes_rows">
-				<source>Rows</source>
-			</trans-unit>
-			<trans-unit id="attributes_selected">
-				<source>Selected</source>
-			</trans-unit>
-			<trans-unit id="attributes_selectionDirection">
-				<source>Selection direction</source>
-			</trans-unit>
-			<trans-unit id="attributes_selectionDirection_none">
-				<source>Not set</source>
-			</trans-unit>
-			<trans-unit id="attributes_selectionDirection_forward">
-				<source>Forward</source>
-			</trans-unit>
-			<trans-unit id="attributes_selectionDirection_backward">
-				<source>Backward</source>
-			</trans-unit>
-			<trans-unit id="attributes_selectionEnd">
-				<source>Selection end</source>
-			</trans-unit>
-			<trans-unit id="attributes_selectionStart">
-				<source>Selection start</source>
-			</trans-unit>
-			<trans-unit id="attributes_size">
-				<source>Size</source>
-			</trans-unit>
-			<trans-unit id="attributes_spellcheck">
-				<source>Spellcheck</source>
-			</trans-unit>
-			<trans-unit id="attributes_spellcheck_none">
-				<source>Not set</source>
-			</trans-unit>
-			<trans-unit id="attributes_spellcheck_true">
-				<source>True</source>
-			</trans-unit>
-			<trans-unit id="attributes_spellcheck_false">
-				<source>False</source>
-			</trans-unit>
-			<trans-unit id="attributes_src">
-				<source>Src</source>
-			</trans-unit>
-			<trans-unit id="attributes_step">
-				<source>Step</source>
-			</trans-unit>
-			<trans-unit id="attributes_style">
-				<source>Style</source>
-			</trans-unit>
-			<trans-unit id="attributes_tabindex">
-				<source>Tabindex</source>
-			</trans-unit>
-			<trans-unit id="attributes_text">
-				<source>Text</source>
-			</trans-unit>
-			<trans-unit id="attributes_title">
-				<source>Title</source>
-			</trans-unit>
-			<trans-unit id="attributes_translate">
-				<source>Translate</source>
-			</trans-unit>
-			<trans-unit id="attributes_translate_none">
-				<source>Not set</source>
-			</trans-unit>
-			<trans-unit id="attributes_translate_yes">
-				<source>Yes</source>
-			</trans-unit>
-			<trans-unit id="attributes_translate_no">
-				<source>No</source>
-			</trans-unit>
-			<trans-unit id="attributes_type">
-				<source>Type</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_button">
-				<source>button</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_checkbox">
-				<source>checkbox</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_color">
-				<source>color</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_date">
-				<source>date</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_datetime">
-				<source>datetime</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_datetime-local">
-				<source>datetime-local</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_email">
-				<source>email</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_file">
-				<source>file</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_hidden">
-				<source>hidden</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_image">
-				<source>image</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_month">
-				<source>month</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_number">
-				<source>number</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_password">
-				<source>password</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_radio">
-				<source>radio</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_range">
-				<source>range</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_reset">
-				<source>reset</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_search">
-				<source>search</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_submit">
-				<source>submit</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_tel">
-				<source>tel</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_text">
-				<source>text</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_time">
-				<source>time</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_url">
-				<source>url</source>
-			</trans-unit>
-			<trans-unit id="attributes_type_week">
-				<source>week</source>
-			</trans-unit>
-			<trans-unit id="attributes_value">
-				<source>Value</source>
-			</trans-unit>
-			<trans-unit id="attributes_width">
-				<source>Width</source>
-			</trans-unit>
-			<trans-unit id="attributes_wrap">
-				<source>Wrap</source>
-			</trans-unit>
-			<trans-unit id="attributes_wrap_none">
-				<source>Not set</source>
-			</trans-unit>
-			<trans-unit id="attributes_wrap_soft">
-				<source>Soft</source>
-			</trans-unit>
-			<trans-unit id="attributes_wrap_hard">
-				<source>Hard</source>
-			</trans-unit>
-			<trans-unit id="options_label">
-				<source>Label Properties</source>
-			</trans-unit>
-			<trans-unit id="label_label">
-				<source>Label</source>
-			</trans-unit>
-			<trans-unit id="label_layout">
-				<source>Label position</source>
-			</trans-unit>
-			<trans-unit id="label_layout_front">
-				<source>In front</source>
-			</trans-unit>
-			<trans-unit id="label_layout_back">
-				<source>After</source>
-			</trans-unit>
-			<trans-unit id="options_legend">
-				<source>Legend Properties</source>
-			</trans-unit>
-			<trans-unit id="legend_legend">
-				<source>Legend</source>
-			</trans-unit>
-			<trans-unit id="options_filters">
-				<source>Filters</source>
-			</trans-unit>
-			<trans-unit id="filters_emptytext">
-				<source>Add a filter</source>
-			</trans-unit>
-			<trans-unit id="filters_alert_title">
-				<source>Adding a filter</source>
-			</trans-unit>
-			<trans-unit id="filters_alert_description">
-				<source>The selected filter is already present</source>
-			</trans-unit>
-			<trans-unit id="filters_dummy_title">
-				<source>No filter selected</source>
-			</trans-unit>
-			<trans-unit id="filters_dummy_description">
-				<source>To add a filter, select one from the dropdown</source>
-			</trans-unit>
-			<trans-unit id="filters_alphabetic">
-				<source>Alphabetic</source>
-			</trans-unit>
-			<trans-unit id="filters_alphanumeric">
-				<source>Alphanumeric</source>
-			</trans-unit>
-			<trans-unit id="filters_currency">
-				<source>Currency</source>
-			</trans-unit>
-			<trans-unit id="filters_digit">
-				<source>Digit</source>
-			</trans-unit>
-			<trans-unit id="filters_integer">
-				<source>Integer</source>
-			</trans-unit>
-			<trans-unit id="filters_lowercase">
-				<source>Lowercase</source>
-			</trans-unit>
-			<trans-unit id="filters_regexp">
-				<source>Regular Expression</source>
-			</trans-unit>
-			<trans-unit id="filters_stripnewlines">
-				<source>Strip New Lines</source>
-			</trans-unit>
-			<trans-unit id="filters_titlecase">
-				<source>Titlecase</source>
-			</trans-unit>
-			<trans-unit id="filters_trim">
-				<source>Trim</source>
-			</trans-unit>
-			<trans-unit id="filters_uppercase">
-				<source>Uppercase</source>
-			</trans-unit>
-			<trans-unit id="filters_properties_allowwhitespace">
-				<source>Allow whitespace</source>
-			</trans-unit>
-			<trans-unit id="filters_properties_decimalpoint">
-				<source>Decimal point</source>
-			</trans-unit>
-			<trans-unit id="filters_properties_thousandseparator">
-				<source>Thousand separator</source>
-			</trans-unit>
-			<trans-unit id="filters_properties_expression">
-				<source>Expression</source>
-			</trans-unit>
-			<trans-unit id="filters_properties_characterlist">
-				<source>Character list</source>
-			</trans-unit>
-			<trans-unit id="filters_properties_none">
-				<source>This filter has no configuration settings</source>
-			</trans-unit>
-			<trans-unit id="options_validation">
-				<source>Validation</source>
-			</trans-unit>
-			<trans-unit id="validation_emptytext">
-				<source>Add a validation rule</source>
-			</trans-unit>
-			<trans-unit id="validation_alert_title">
-				<source>Adding a validation rule</source>
-			</trans-unit>
-			<trans-unit id="validation_alert_description">
-				<source>The selected validation rule is already present</source>
-			</trans-unit>
-			<trans-unit id="validation_dummy_title">
-				<source>No validation rule selected</source>
-			</trans-unit>
-			<trans-unit id="validation_dummy_description">
-				<source>To add a validation rule, select one from the dropdown</source>
-			</trans-unit>
-			<trans-unit id="validation_alphabetic">
-				<source>Alphabetic</source>
-			</trans-unit>
-			<trans-unit id="validation_alphanumeric">
-				<source>Alphanumeric</source>
-			</trans-unit>
-			<trans-unit id="validation_between">
-				<source>Between</source>
-			</trans-unit>
-			<trans-unit id="validation_date">
-				<source>Date</source>
-			</trans-unit>
-			<trans-unit id="validation_digit">
-				<source>Digit</source>
-			</trans-unit>
-			<trans-unit id="validation_email">
-				<source>Email address</source>
-			</trans-unit>
-			<trans-unit id="validation_equals">
-				<source>Equals</source>
-			</trans-unit>
-			<trans-unit id="validation_fileallowedtypes">
-				<source>Allowed mimetypes for file</source>
-			</trans-unit>
-			<trans-unit id="validation_filemaximumsize">
-				<source>Maximum size for file (bytes)</source>
-			</trans-unit>
-			<trans-unit id="validation_fileminimumsize">
-				<source>Minimum size for file (bytes)</source>
-			</trans-unit>
-			<trans-unit id="validation_float">
-				<source>Float</source>
-			</trans-unit>
-			<trans-unit id="validation_greaterthan">
-				<source>Greater than</source>
-			</trans-unit>
-			<trans-unit id="validation_inarray">
-				<source>In array</source>
-			</trans-unit>
-			<trans-unit id="validation_integer">
-				<source>Integer</source>
-			</trans-unit>
-			<trans-unit id="validation_ip">
-				<source>Ip address</source>
-			</trans-unit>
-			<trans-unit id="validation_length">
-				<source>Length</source>
-			</trans-unit>
-			<trans-unit id="validation_lessthan">
-				<source>Less than</source>
-			</trans-unit>
-			<trans-unit id="validation_regexp">
-				<source>Regular Expression</source>
-			</trans-unit>
-			<trans-unit id="validation_required">
-				<source>Required</source>
-			</trans-unit>
-			<trans-unit id="validation_uri">
-				<source>Uniform Resource Identifier</source>
-			</trans-unit>
-			<trans-unit id="validation_properties_message">
-				<source>Message</source>
-			</trans-unit>
-			<trans-unit id="validation_properties_error">
-				<source>Error</source>
-			</trans-unit>
-			<trans-unit id="validation_properties_showmessage">
-				<source>Show message in label</source>
-			</trans-unit>
-			<trans-unit id="validation_properties_allowwhitespace">
-				<source>Allow whitespace</source>
-			</trans-unit>
-			<trans-unit id="validation_properties_minimum">
-				<source>Minimum</source>
-			</trans-unit>
-			<trans-unit id="validation_properties_maximum">
-				<source>Maximum</source>
-			</trans-unit>
-			<trans-unit id="validation_properties_inclusive">
-				<source>Inclusive</source>
-			</trans-unit>
-			<trans-unit id="validation_properties_format">
-				<source>Format</source>
-			</trans-unit>
-			<trans-unit id="validation_properties_field">
-				<source>Field</source>
-			</trans-unit>
-			<trans-unit id="validation_properties_array">
-				<source>Array (Comma separated)</source>
-			</trans-unit>
-			<trans-unit id="validation_properties_expression">
-				<source>Expression</source>
-			</trans-unit>
-			<trans-unit id="validation_properties_types">
-				<source>Mime types</source>
-			</trans-unit>
-			<trans-unit id="options_fieldoptions">
-				<source>Field options</source>
-			</trans-unit>
-			<trans-unit id="fieldoptions_emptytext">
-				<source>No options to display</source>
-			</trans-unit>
-			<trans-unit id="fieldoptions_text">
-				<source>Text</source>
-			</trans-unit>
-			<trans-unit id="fieldoptions_value">
-				<source>Value</source>
-			</trans-unit>
-			<trans-unit id="fieldoptions_delete">
-				<source>Delete</source>
-			</trans-unit>
-			<trans-unit id="fieldoptions_selected">
-				<source>Selected</source>
-			</trans-unit>
-			<trans-unit id="fieldoptions_button_add">
-				<source>Add option</source>
-			</trans-unit>
-			<trans-unit id="fieldoptions_new">
-				<source>New option</source>
-			</trans-unit>
-			<trans-unit id="options_various">
-				<source>Various Properties</source>
-			</trans-unit>
-			<trans-unit id="various_properties_name">
-				<source>Name</source>
-			</trans-unit>
-			<trans-unit id="various_properties_content">
-				<source>Content</source>
-			</trans-unit>
-			<trans-unit id="various_properties_headingsize">
-				<source>Heading size</source>
-			</trans-unit>
-			<trans-unit id="various_properties_prefix">
-				<source>Show prefix</source>
-			</trans-unit>
-			<trans-unit id="various_properties_suffix">
-				<source>Show suffix</source>
-			</trans-unit>
-			<trans-unit id="various_properties_text">
-				<source>Text</source>
-			</trans-unit>
-			<trans-unit id="various_properties_middlename">
-				<source>Show middle name</source>
-			</trans-unit>
-			<trans-unit id="left_form">
-				<source>Form</source>
-			</trans-unit>
-			<trans-unit id="form_prefix">
-				<source>Prefix</source>
-			</trans-unit>
-			<trans-unit id="form_behaviour">
-				<source>Behaviour</source>
-			</trans-unit>
-			<trans-unit id="behaviour_confirmation_page">
-				<source>Confirmation page</source>
-			</trans-unit>
-			<trans-unit id="form_postprocessor">
-				<source>Post Processors</source>
-			</trans-unit>
-			<trans-unit id="postprocessor_emptytext">
-				<source>Add a Post Processor</source>
-			</trans-unit>
-			<trans-unit id="postprocessor_alert_title">
-				<source>Adding a Post Processor</source>
-			</trans-unit>
-			<trans-unit id="postprocessor_alert_description">
-				<source>The selected post processor is already present</source>
-			</trans-unit>
-			<trans-unit id="postprocessor_mail">
-				<source>Send email</source>
-			</trans-unit>
-			<trans-unit id="postprocessor_redirect">
-				<source>Redirect</source>
-			</trans-unit>
-			<trans-unit id="postprocessor_dummy_title">
-				<source>No post processor selected</source>
-			</trans-unit>
-			<trans-unit id="postprocessor_dummy_description">
-				<source>To add a post processor, select one from the dropdown</source>
-			</trans-unit>
-			<trans-unit id="postprocessor_properties_recipientemail">
-				<source>Email address of the recipient</source>
-			</trans-unit>
-			<trans-unit id="postprocessor_properties_senderemail">
-				<source>Email address of the sender</source>
-			</trans-unit>
-			<trans-unit id="postprocessor_properties_subject">
-				<source>Subject</source>
-			</trans-unit>
-			<trans-unit id="postprocessor_properties_destination">
-				<source>Destination to redirect to</source>
-			</trans-unit>
-			<trans-unit id="prefix_prefix">
-				<source>Prefix</source>
-			</trans-unit>
-			<trans-unit id="elements_dummy_title">
-				<source>You haven't added any elements yet!</source>
-			</trans-unit>
-			<trans-unit id="elements_dummy_description">
-				<source>To get started, drag an element from the left panel onto this area</source>
-			</trans-unit>
-			<trans-unit id="elements_button_delete">
-				<source>Delete this element</source>
-			</trans-unit>
-			<trans-unit id="elements_button_edit">
-				<source>Edit this element</source>
-			</trans-unit>
-			<trans-unit id="elements_confirm_delete_title">
-				<source>Delete element</source>
-			</trans-unit>
-			<trans-unit id="elements_confirm_delete_description">
-				<source>Are you sure you want to delete the selected element?</source>
-			</trans-unit>
-			<trans-unit id="elements_label">
-				<source>Edit this label</source>
-			</trans-unit>
-			<trans-unit id="elements_label_email">
-				<source>Email</source>
-			</trans-unit>
-			<trans-unit id="elements_label_prefix">
-				<source>Prefix</source>
-			</trans-unit>
-			<trans-unit id="elements_label_firstname">
-				<source>First name</source>
-			</trans-unit>
-			<trans-unit id="elements_label_middlename">
-				<source>Middle name</source>
-			</trans-unit>
-			<trans-unit id="elements_label_lastname">
-				<source>Last name</source>
-			</trans-unit>
-			<trans-unit id="elements_label_suffix">
-				<source>Suffix</source>
-			</trans-unit>
-			<trans-unit id="elements_legend">
-				<source>Edit this legend</source>
-			</trans-unit>
-			<trans-unit id="elements_legend_name">
-				<source>Full name</source>
-			</trans-unit>
-			<trans-unit id="elements_header_content">
-				<source>Edit this header</source>
-			</trans-unit>
-			<trans-unit id="elements_textblock_content">
-				<source>Edit this textblock</source>
-			</trans-unit>
-			<trans-unit id="elements_option_1">
-				<source>Option 1</source>
-			</trans-unit>
-			<trans-unit id="elements_option_2">
-				<source>Option 2</source>
-			</trans-unit>
-			<trans-unit id="elements_option_3">
-				<source>Option 3</source>
-			</trans-unit>
-			<trans-unit id="elements_value_1">
-				<source>Value 1</source>
-			</trans-unit>
-			<trans-unit id="elements_value_2">
-				<source>Value 2</source>
-			</trans-unit>
-			<trans-unit id="elements_value_3">
-				<source>Value 3</source>
-			</trans-unit>
-		</body>
-	</file>
-</xliff>
diff --git a/typo3/sysext/form/Resources/Private/Layouts/Default.html b/typo3/sysext/form/Resources/Private/Layouts/Default.html
deleted file mode 100644
index 54d9aa0bb6bc6344e981179f79d369c297f47bec..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Layouts/Default.html
+++ /dev/null
@@ -1 +0,0 @@
-<f:render section="main" />
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/AdditionalElements/Label.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/AdditionalElements/Label.html
deleted file mode 100644
index e39cf1f7bad6ff59e99e08c7cfa14ed0b12edba6..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/AdditionalElements/Label.html
+++ /dev/null
@@ -1 +0,0 @@
-<label>{model.additionalArguments.label}</label>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/AdditionalElements/Legend.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/AdditionalElements/Legend.html
deleted file mode 100644
index 5a70ce3ee2eec493348c27a75afffb1c6453d58a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/AdditionalElements/Legend.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<f:if condition="{model.additionalArguments.legend}">
-    <legend>{model.additionalArguments.legend}</legend>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/ContainerElements/Checkboxgroup.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/ContainerElements/Checkboxgroup.html
deleted file mode 100644
index 1018baa6079a270a85ebba3e51dce7fb0f3a5f23..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/ContainerElements/Checkboxgroup.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<f:if condition="{model.additionalArguments.atLeastOneCheckedChildElement}">
-	<f:if condition="{model.showElement}">
-		<f:then>
-			<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-				<fieldset
-				<f:for each="{model.htmlAttributes}" as="htmAttributeValue" key="htmAttributeKey">
-					{htmAttributeKey}="{htmAttributeValue}"
-				</f:for>
-				>
-					{f:render(partial: '{themeName}/Confirmation/AdditionalElements/Legend', arguments: {model: model, themeName: themeName})}
-					<ol>
-						<f:for each="{model.childElements}" as="element">
-							<f:render partial="{themeName}/Confirmation/{element.partialPath}" arguments="{model: element, themeName: themeName}" />
-						</f:for>
-					</ol>
-				</fieldset>
-			</li>
-		</f:then>
-		<f:else>
-			<f:for each="{model.childElements}" as="element">
-				<f:render partial="{themeName}/Confirmation/{element.partialPath}" arguments="{model: element, themeName: themeName}" />
-			</f:for>
-		</f:else>
-	</f:if>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/ContainerElements/Fieldset.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/ContainerElements/Fieldset.html
deleted file mode 100644
index 945aa07a55961d86c27520c1de7f5271a630bb6d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/ContainerElements/Fieldset.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<f:if condition="{model.childElements.0}">
-	<f:if condition="{model.showElement}">
-		<f:then>
-			<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-				<fieldset
-				<f:for each="{model.htmlAttributes}" as="htmAttributeValue" key="htmAttributeKey">
-					{htmAttributeKey}="{htmAttributeValue}"
-				</f:for>
-				>
-					{f:render(partial: '{themeName}/Confirmation/AdditionalElements/Legend', arguments: {model: model, themeName: themeName})}
-					<ol>
-						<f:for each="{model.childElements}" as="element">
-							<f:render partial="{themeName}/Confirmation/{element.partialPath}" arguments="{model: element, themeName: themeName}" />
-						</f:for>
-					</ol>
-				</fieldset>
-			</li>
-		</f:then>
-		<f:else>
-			<f:for each="{model.childElements}" as="element">
-				<f:render partial="{themeName}/Confirmation/{element.partialPath}" arguments="{model: element, themeName: themeName}" />
-			</f:for>
-		</f:else>
-	</f:if>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/ContainerElements/Form.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/ContainerElements/Form.html
deleted file mode 100644
index b3fb2131f44d7fddbfdc7ff4da6fca1e620f979e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/ContainerElements/Form.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<f:form
-	class="{model.additionalArguments.class}"
-	dir="{model.additionalArguments.dir}"
-	id="{model.additionalArguments.id}"
-	lang="{model.additionalArguments.lang}"
-	style="{model.additionalArguments.style}"
-	title="{model.additionalArguments.title}"
-	accesskey="{model.additionalArguments.accesskey}"
-	tabindex="{model.additionalArguments.tabindex}"
-	onclick="{model.additionalArguments.onclick}"
-
-	enctype="{model.additionalArguments.enctype}"
-	method="{model.additionalArguments.method}"
-	name="{model.additionalArguments.name}"
-	onreset="{model.additionalArguments.onreset}"
-	onsubmit="{model.additionalArguments.onsubmit}"
-
-	absolute="{model.additionalArguments.absolute}"
-	action="dispatchConfirmationButtonClick"
-	actionUri="{model.additionalArguments.actionUri}"
-	addQueryString="{model.additionalArguments.addQueryString}"
-	additionalAttributes="{model.htmlAttributes}"
-	additionalParams="{model.additionalArguments.additionalParams}"
-	arguments="{model.additionalArguments.arguments}"
-	argumentsToBeExcludedFromQueryString="{model.additionalArguments.argumentsToBeExcludedFromQueryString}"
-	controller="Frontend"
-	extensionName="Form"
-
-	format="{f:if(condition:'{model.additionalArguments.format}',then:'{model.additionalArguments.format}')}"
-	hiddenFieldClassName="{model.additionalArguments.hiddenFieldClassName}"
-
-	object="{model}"
-
-	pageType="{model.additionalArguments.pageType}"
-	pageUid="{model.additionalArguments.pageUid}"
-	pluginName="Form"
-	section="{model.additionalArguments.section}">
-
-	<ol>
-		<f:for each="{model.childElements}" as="element">
-			<f:render partial="{themeName}/Confirmation/{element.partialPath}" arguments="{model: element, themeName: themeName}" />
-		</f:for>
-	</ol>
-
-	<ol>
-		<li class="csc-form-confirmation-false">
-			<f:form.submit name="confirmation-false" value="<f:translate key='tx_form_view_confirmation.donotconfirm'/>"><f:translate key='tx_form_view_confirmation.donotconfirm'/></f:form.submit>
-		</li>
-		<li class="csc-form-confirmation-true">
-			<f:form.submit name="confirmation-true" value="<f:translate key='tx_form_view_confirmation.confirm'/>"><f:translate key='tx_form_view_confirmation.confirm'/></f:form.submit>
-		</li>
-	</ol>
-</f:form>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/ContainerElements/Radiogroup.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/ContainerElements/Radiogroup.html
deleted file mode 100644
index 1018baa6079a270a85ebba3e51dce7fb0f3a5f23..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/ContainerElements/Radiogroup.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<f:if condition="{model.additionalArguments.atLeastOneCheckedChildElement}">
-	<f:if condition="{model.showElement}">
-		<f:then>
-			<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-				<fieldset
-				<f:for each="{model.htmlAttributes}" as="htmAttributeValue" key="htmAttributeKey">
-					{htmAttributeKey}="{htmAttributeValue}"
-				</f:for>
-				>
-					{f:render(partial: '{themeName}/Confirmation/AdditionalElements/Legend', arguments: {model: model, themeName: themeName})}
-					<ol>
-						<f:for each="{model.childElements}" as="element">
-							<f:render partial="{themeName}/Confirmation/{element.partialPath}" arguments="{model: element, themeName: themeName}" />
-						</f:for>
-					</ol>
-				</fieldset>
-			</li>
-		</f:then>
-		<f:else>
-			<f:for each="{model.childElements}" as="element">
-				<f:render partial="{themeName}/Confirmation/{element.partialPath}" arguments="{model: element, themeName: themeName}" />
-			</f:for>
-		</f:else>
-	</f:if>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Checkbox.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Checkbox.html
deleted file mode 100644
index 734eb4403aa336c7fbc356e78247a4ad1650979f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Checkbox.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<f:if condition="{model.showElement}">
-	<f:if condition="{model.additionalArguments.checked} == 'checked'">
-		<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-			{f:render(partial: '{themeName}/Confirmation/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-			<f:if condition="{model.additionalArguments.value}">{model.additionalArguments.value}</f:if>
-		</li>
-	</f:if>
-</f:if>
-
-<f:if condition="{model.additionalArguments.checked} == 'checked'">
-	<f:if condition="{model.additionalArguments.multiple}">
-		<f:then>
-			<f:form.hidden
-				class="{model.additionalArguments.class}"
-				dir="{model.additionalArguments.dir}"
-				id="{model.additionalArguments.id}"
-				lang="{model.additionalArguments.lang}"
-				style="{model.additionalArguments.style}"
-				title="{model.additionalArguments.title}"
-				accesskey="{model.additionalArguments.accesskey}"
-				tabindex="{model.additionalArguments.tabindex}"
-				onclick="{model.additionalArguments.onclick}"
-
-				name="{model.additionalArguments.prefix}[{model.additionalArguments.name}][{model.name}]"
-				value="<f:if condition='{model.additionalArguments.value}'><f:then>{model.additionalArguments.value}</f:then><f:else>{model.additionalArguments.name}-{model.elementCounter}</f:else></f:if>"
-
-				additionalAttributes="{model.htmlAttributes}"
-			/>
-		</f:then>
-		<f:else>
-			<f:form.hidden
-				class="{model.additionalArguments.class}"
-				dir="{model.additionalArguments.dir}"
-				id="{model.additionalArguments.id}"
-				lang="{model.additionalArguments.lang}"
-				style="{model.additionalArguments.style}"
-				title="{model.additionalArguments.title}"
-				accesskey="{model.additionalArguments.accesskey}"
-				tabindex="{model.additionalArguments.tabindex}"
-				onclick="{model.additionalArguments.onclick}"
-
-				name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-				value="<f:if condition='{model.additionalArguments.value}'><f:then>{model.additionalArguments.value}</f:then><f:else>{model.additionalArguments.name}-{model.elementCounter}</f:else></f:if>"
-
-				additionalAttributes="{model.htmlAttributes}"
-			/>
-		</f:else>
-	</f:if>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Hidden.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Hidden.html
deleted file mode 100644
index 6f3c765a6eb97a9a4fbbcc9229800899a208fdec..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Hidden.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-	<f:form.hidden
-		class="{model.additionalArguments.class}"
-		dir="{model.additionalArguments.dir}"
-		id="{model.additionalArguments.id}"
-		lang="{model.additionalArguments.lang}"
-		style="{model.additionalArguments.style}"
-		title="{model.additionalArguments.title}"
-		accesskey="{model.additionalArguments.accesskey}"
-		tabindex="{model.additionalArguments.tabindex}"
-		onclick="{model.additionalArguments.onclick}"
-
-		name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-		value="{model.additionalArguments.value}"
-
-		additionalAttributes="{model.htmlAttributes}"
-	/>
-</li>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Imagebutton.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Imagebutton.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Input.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Input.html
deleted file mode 100644
index e9c809fd24280319419570cfda2378acdc90901b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Input.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Confirmation/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-		{model.additionalArguments.value}
-	</li>
-</f:if>
-
-<f:form.hidden
-	class="{model.additionalArguments.class}"
-	dir="{model.additionalArguments.dir}"
-	id="{model.additionalArguments.id}"
-	lang="{model.additionalArguments.lang}"
-	style="{model.additionalArguments.style}"
-	title="{model.additionalArguments.title}"
-	accesskey="{model.additionalArguments.accesskey}"
-	tabindex="{model.additionalArguments.tabindex}"
-	onclick="{model.additionalArguments.onclick}"
-
-	name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-	value="{model.additionalArguments.value}"
-
-	additionalAttributes="{model.htmlAttributes}"
-/>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/InputTypeButton.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/InputTypeButton.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Password.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Password.html
deleted file mode 100644
index f7e3d8cdb3b5e2a289c330831f5d26ee4e942995..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Password.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<f:form.hidden
-	class="{model.additionalArguments.class}"
-	dir="{model.additionalArguments.dir}"
-	id="{model.additionalArguments.id}"
-	lang="{model.additionalArguments.lang}"
-	style="{model.additionalArguments.style}"
-	title="{model.additionalArguments.title}"
-	accesskey="{model.additionalArguments.accesskey}"
-	tabindex="{model.additionalArguments.tabindex}"
-	onclick="{model.additionalArguments.onclick}"
-
-	name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-	value="{model.additionalArguments.value}"
-
-	additionalAttributes="{model.htmlAttributes}"
-/>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Radio.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Radio.html
deleted file mode 100644
index 0667ba983c66001c3c5b8eab1c671ab42b871b55..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Radio.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<f:if condition="{model.showElement}">
-	<f:if condition="{model.additionalArguments.checked} == 'checked'">
-		<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-			{f:render(partial: '{themeName}/Confirmation/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-			<f:if condition="{model.additionalArguments.value}">{model.additionalArguments.value}</f:if>
-		</li>
-	</f:if>
-</f:if>
-
-<f:if condition="{model.additionalArguments.checked} == 'checked'">
-	<f:form.hidden
-		class="{model.additionalArguments.class}"
-		dir="{model.additionalArguments.dir}"
-		id="{model.additionalArguments.id}"
-		lang="{model.additionalArguments.lang}"
-		style="{model.additionalArguments.style}"
-		title="{model.additionalArguments.title}"
-		accesskey="{model.additionalArguments.accesskey}"
-		tabindex="{model.additionalArguments.tabindex}"
-		onclick="{model.additionalArguments.onclick}"
-
-		name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-		value="<f:if condition='{model.additionalArguments.value}'><f:then>{model.additionalArguments.value}</f:then><f:else>{model.additionalArguments.name}-{model.elementCounter}</f:else></f:if>"
-
-		additionalAttributes="{model.htmlAttributes}"
-	/>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Reset.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Reset.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Select.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Select.html
deleted file mode 100644
index 2baa6bdbca2a968ddd9f7e3354fff93e2df0d58d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Select.html
+++ /dev/null
@@ -1,111 +0,0 @@
-{namespace form=TYPO3\CMS\Form\ViewHelpers}
-
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Confirmation/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-		<ol>
-</f:if>
-<f:for each="{form:aggregateSelectOptions(model:model)}" as="option">
-	<f:if condition="{option.options}">
-		<f:then>
-				<f:for each="{option.options}" as="optgroupOption">
-					<f:if condition="{optgroupOption.selected}">
-						<f:if condition="{model.showElement}">
-							<li class="csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-								{optgroupOption.label}
-							</li>
-						</f:if>
-						<f:if condition="{model.additionalArguments.multiple}">
-							<f:then>
-								<f:form.hidden
-									class="{model.additionalArguments.class}"
-									dir="{model.additionalArguments.dir}"
-									id="{model.additionalArguments.id}"
-									lang="{model.additionalArguments.lang}"
-									style="{model.additionalArguments.style}"
-									title="{model.additionalArguments.title}"
-									accesskey="{model.additionalArguments.accesskey}"
-									tabindex="{model.additionalArguments.tabindex}"
-									onclick="{model.additionalArguments.onclick}"
-
-									name="{model.additionalArguments.prefix}[{model.additionalArguments.name}][]"
-									value="{optgroupOption.value}"
-
-									additionalAttributes="{model.htmlAttributes}"
-								/>
-							</f:then>
-							<f:else>
-								<f:form.hidden
-									class="{model.additionalArguments.class}"
-									dir="{model.additionalArguments.dir}"
-									id="{model.additionalArguments.id}"
-									lang="{model.additionalArguments.lang}"
-									style="{model.additionalArguments.style}"
-									title="{model.additionalArguments.title}"
-									accesskey="{model.additionalArguments.accesskey}"
-									tabindex="{model.additionalArguments.tabindex}"
-									onclick="{model.additionalArguments.onclick}"
-
-									name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-									value="{optgroupOption.value}"
-
-									additionalAttributes="{model.htmlAttributes}"
-								/>
-							</f:else>
-						</f:if>
-					</f:if>
-				</f:for>
-		</f:then>
-		<f:else>
-			<f:if condition="{option.selected}">
-				<f:if condition="{model.showElement}">
-					<li class="csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-						{option.label}
-					</li>
-				</f:if>
-				<f:if condition="{model.additionalArguments.multiple}">
-					<f:then>
-						<f:form.hidden
-							class="{model.additionalArguments.class}"
-							dir="{model.additionalArguments.dir}"
-							id="{model.additionalArguments.id}"
-							lang="{model.additionalArguments.lang}"
-							style="{model.additionalArguments.style}"
-							title="{model.additionalArguments.title}"
-							accesskey="{model.additionalArguments.accesskey}"
-							tabindex="{model.additionalArguments.tabindex}"
-							onclick="{model.additionalArguments.onclick}"
-
-							name="{model.additionalArguments.prefix}[{model.additionalArguments.name}][]"
-							value="{option.value}"
-
-							additionalAttributes="{model.htmlAttributes}"
-						/>
-					</f:then>
-					<f:else>
-						<f:form.hidden
-							class="{model.additionalArguments.class}"
-							dir="{model.additionalArguments.dir}"
-							id="{model.additionalArguments.id}"
-							lang="{model.additionalArguments.lang}"
-							style="{model.additionalArguments.style}"
-							title="{model.additionalArguments.title}"
-							accesskey="{model.additionalArguments.accesskey}"
-							tabindex="{model.additionalArguments.tabindex}"
-							onclick="{model.additionalArguments.onclick}"
-
-							name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-							value="{option.value}"
-
-							additionalAttributes="{model.htmlAttributes}"
-						/>
-					</f:else>
-				</f:if>
-			</f:if>
-		</f:else>
-	</f:if>
-</f:for>
-<f:if condition="{model.showElement}">
-		</ol>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Submit.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Submit.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Textarea.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Textarea.html
deleted file mode 100644
index eaedfd0856f90d46192acd7fe8cbcb8d069a1d82..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Textarea.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Confirmation/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-		{model.additionalArguments.text}
-	</li>
-</f:if>
-
-<f:form.hidden
-	class="{model.additionalArguments.class}"
-	dir="{model.additionalArguments.dir}"
-	id="{model.additionalArguments.id}"
-	lang="{model.additionalArguments.lang}"
-	style="{model.additionalArguments.style}"
-	title="{model.additionalArguments.title}"
-	accesskey="{model.additionalArguments.accesskey}"
-	tabindex="{model.additionalArguments.tabindex}"
-	onclick="{model.additionalArguments.onclick}"
-
-	name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-	value="{model.additionalArguments.text}"
-
-	additionalAttributes="{model.htmlAttributes}"
-/>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Textblock.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Textblock.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Textfield.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Textfield.html
deleted file mode 100644
index 4145a534afe10d0d1f639d662a1d91eb6783276a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Textfield.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Confirmation/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-		{model.additionalArguments.value}
-	</li>
-</f:if>
-
-<f:form.hidden
-	class="{model.additionalArguments.class}"
-	dir="{model.additionalArguments.dir}"
-	id="{model.additionalArguments.id}"
-	lang="{model.additionalArguments.lang}"
-	style="{model.additionalArguments.style}"
-	title="{model.additionalArguments.title}"
-	accesskey="{model.additionalArguments.accesskey}"
-	tabindex="{model.additionalArguments.tabindex}"
-	onclick="{model.additionalArguments.onclick}"
-
-	name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-	value="{model.additionalArguments.value}"
-
-	additionalAttributes="{model.htmlAttributes}"
-/>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Upload.html b/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Upload.html
deleted file mode 100644
index fae3e351b939ab0e2045d8782d31154fc6bb07bd..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Upload.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Confirmation/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-		<f:for each="{model.additionalArguments.uploadedFiles}" as="uploadedFile">
-			{uploadedFile.name}<br />
-		</f:for>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/AdditionalElements/Label.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/AdditionalElements/Label.html
deleted file mode 100644
index 9dc9dfbeddbfa1b3d0678a3121c35fffc6246524..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/AdditionalElements/Label.html
+++ /dev/null
@@ -1 +0,0 @@
-<em>{model.additionalArguments.label}</em>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/AdditionalElements/Legend.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/AdditionalElements/Legend.html
deleted file mode 100644
index e6420befc51c2c7cb5b493d2f0c45ac15a2e0372..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/AdditionalElements/Legend.html
+++ /dev/null
@@ -1 +0,0 @@
-{model.additionalArguments.legend}
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/ContainerElements/Checkboxgroup.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/ContainerElements/Checkboxgroup.html
deleted file mode 100644
index 4fa40c7046a27a7dde1056b30dfb59fb2bd167a0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/ContainerElements/Checkboxgroup.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<f:if condition="{model.additionalArguments.atLeastOneCheckedChildElement}">
-	<f:if condition="{model.showElement}">
-		<f:then>
-			<tr class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-				<td colspan="2">
-					<table cellspacing="0" style="padding-left: 20px; margin-bottom: 20px;">
-						<f:if condition="{model.additionalArguments.legend}">
-							<thead>
-								<tr>
-									<th colspan="2" align="left">
-										{f:render(partial: 'AdditionalElements/Legend', arguments: {model: model})}
-									</th>
-								</tr>
-							</thead>
-						</f:if>
-						<tbody>
-							<f:for each="{model.childElements}" as="element">
-								<f:render partial="{element.partialPath}" arguments="{model: element}" />
-							</f:for>
-						</tbody>
-					</table>
-				</td>
-			</tr>
-		</f:then>
-		<f:else>
-			<f:for each="{model.childElements}" as="element">
-				<f:render partial="{element.partialPath}" arguments="{model: element}" />
-			</f:for>
-		</f:else>
-	</f:if>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/ContainerElements/Fieldset.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/ContainerElements/Fieldset.html
deleted file mode 100644
index 8b4a9e74a669d38a3659e82d531d83f82271609c..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/ContainerElements/Fieldset.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<f:if condition="{model.childElements.0}">
-	<f:if condition="{model.showElement}">
-		<f:then>
-			<tr class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-				<td colspan="2">
-					<table cellspacing="0" style="padding-left: 20px; margin-bottom: 20px;">
-						<f:if condition="{model.additionalArguments.legend}">
-							<thead>
-								<tr>
-									<th colspan="2" align="left">
-										{f:render(partial: 'AdditionalElements/Legend', arguments: {model: model})}
-									</th>
-								</tr>
-							</thead>
-						</f:if>
-						<tbody>
-							<f:for each="{model.childElements}" as="element">
-								<f:render partial="{element.partialPath}" arguments="{model: element}" />
-							</f:for>
-						</tbody>
-					</table>
-				</td>
-			</tr>
-		</f:then>
-		<f:else>
-			<f:for each="{model.childElements}" as="element">
-				<f:render partial="{element.partialPath}" arguments="{model: element}" />
-			</f:for>
-		</f:else>
-	</f:if>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/ContainerElements/Form.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/ContainerElements/Form.html
deleted file mode 100644
index dc4d724a604f254f94443ded4d12ffac324155a4..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/ContainerElements/Form.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<html>
-	<head>
-		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-	</head>
-	<body>
-		<table cellspacing="0">
-			<tbody>
-			<f:for each="{model.childElements}" as="element">
-				<f:render partial="{element.partialPath}" arguments="{model: element}" />
-			</f:for>
-			</tbody>
-		</table>
-	</body>
-</html>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/ContainerElements/Radiogroup.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/ContainerElements/Radiogroup.html
deleted file mode 100644
index 4fa40c7046a27a7dde1056b30dfb59fb2bd167a0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/ContainerElements/Radiogroup.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<f:if condition="{model.additionalArguments.atLeastOneCheckedChildElement}">
-	<f:if condition="{model.showElement}">
-		<f:then>
-			<tr class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-				<td colspan="2">
-					<table cellspacing="0" style="padding-left: 20px; margin-bottom: 20px;">
-						<f:if condition="{model.additionalArguments.legend}">
-							<thead>
-								<tr>
-									<th colspan="2" align="left">
-										{f:render(partial: 'AdditionalElements/Legend', arguments: {model: model})}
-									</th>
-								</tr>
-							</thead>
-						</f:if>
-						<tbody>
-							<f:for each="{model.childElements}" as="element">
-								<f:render partial="{element.partialPath}" arguments="{model: element}" />
-							</f:for>
-						</tbody>
-					</table>
-				</td>
-			</tr>
-		</f:then>
-		<f:else>
-			<f:for each="{model.childElements}" as="element">
-				<f:render partial="{element.partialPath}" arguments="{model: element}" />
-			</f:for>
-		</f:else>
-	</f:if>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Button.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Button.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/ButtonTag.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/ButtonTag.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Checkbox.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Checkbox.html
deleted file mode 100644
index a5d44397423efbd650badf82912dcd8665b76c33..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Checkbox.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<f:if condition="{model.showElement}">
-<f:if condition="{model.additionalArguments.checked} == 'checked'">
-<tr class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-  <td style="width: 200px;">
-    {f:render(partial: 'AdditionalElements/Label', arguments: {model: model})}
-  </td>
-  <td>{model.additionalArguments.value}</td>
-</tr>
-</f:if>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/ContentElement.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/ContentElement.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Header.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Header.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Hidden.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Hidden.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Imagebutton.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Imagebutton.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Input.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Input.html
deleted file mode 100644
index 3a539949329eaa4fba65a9eb7df6771d689ec010..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Input.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<f:if condition="{model.showElement}">
-<tr class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-  <td style="width: 200px;">
-    {f:render(partial: 'AdditionalElements/Label', arguments: {model: model})}
-  </td>
-  <td>{model.additionalArguments.value}</td>
-</tr>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/InputTypeButton.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/InputTypeButton.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Password.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Password.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Radio.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Radio.html
deleted file mode 100644
index 73e16d87c7b196f266ac420d99db139d59250006..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Radio.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<f:if condition="{model.showElement}">
-<f:if condition="{model.additionalArguments.checked} == 'checked'">
-<tr class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-  <td style="width: 200px;">
-    {f:render(partial: 'AdditionalElements/Label', arguments: {model: model})}
-  </td>
-  <td>{model.additionalArguments.value}</td>
-</tr>
-</f:if>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Reset.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Reset.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Select.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Select.html
deleted file mode 100644
index e071ed69d0c42e3e97a5f0c5cb0083fa88902fb2..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Select.html
+++ /dev/null
@@ -1,26 +0,0 @@
-{namespace form=TYPO3\CMS\Form\ViewHelpers}
-<f:if condition="{model.showElement}">
-<tr class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-  <td style="width: 200px;">
-    {f:render(partial: 'AdditionalElements/Label', arguments: {model: model})}
-  </td>
-  <td>
-<f:for each="{form:aggregateSelectOptions(model:model)}" as="option">
-<f:if condition="{option.options}">
-<f:then>
-<f:for each="{option.options}" as="optgroupOption">
-<f:if condition="{optgroupOption.selected}">
-    <div class="csc-form-element csc-form-element-{model.elementTypeLowerCase}">{optgroupOption.label}</div>
-</f:if>
-</f:for>
-</f:then>
-<f:else>
-<f:if condition="{option.selected}">
-    <div class="csc-form-element csc-form-element-{model.elementTypeLowerCase}">{option.label}</div>
-</f:if>
-</f:else>
-</f:if>
-</f:for>
-  </td>
-</tr>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Submit.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Submit.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Textarea.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Textarea.html
deleted file mode 100644
index 367fe2a72231783f14f8e2d83891cb145605af7c..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Textarea.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<f:if condition="{model.showElement}">
-<tr class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-  <td style="width: 200px;" valign="top">
-    {f:render(partial: 'AdditionalElements/Label', arguments: {model: model})}
-  </td>
-  <td>{model.additionalArguments.text}</td>
-</tr>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Textblock.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Textblock.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Textfield.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Textfield.html
deleted file mode 100644
index 3a539949329eaa4fba65a9eb7df6771d689ec010..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Textfield.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<f:if condition="{model.showElement}">
-<tr class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-  <td style="width: 200px;">
-    {f:render(partial: 'AdditionalElements/Label', arguments: {model: model})}
-  </td>
-  <td>{model.additionalArguments.value}</td>
-</tr>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Upload.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Upload.html
deleted file mode 100644
index 9459c26689f66d33428c7f55c42582a128129b17..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Html/FlatElements/Upload.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<f:if condition="{model.showElement}">
-<tr class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-  <td style="width: 200px;">
-    {f:render(partial: 'AdditionalElements/Label', arguments: {model: model})}
-  </td>
-  <td>
-<f:for each="{model.additionalArguments.uploadedFiles}" as="uploadedFile">{uploadedFile.name}<br /></f:for>
-  </td>
-</tr>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/ContainerElements/Checkboxgroup.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/ContainerElements/Checkboxgroup.html
deleted file mode 100644
index 2a2a5e64fb17797eee1e359f449e3670ac9e26f1..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/ContainerElements/Checkboxgroup.html
+++ /dev/null
@@ -1 +0,0 @@
-{namespace form=TYPO3\CMS\Form\ViewHelpers}<f:if condition="{model.additionalArguments.atLeastOneCheckedChildElement}"><f:if condition="{model.showElement}"><f:then><form:plainMail labelContent="{model}" newLineAfterLabel="1" indent="4" /><f:for each="{model.childElements}" as="element"><f:render partial="{element.partialPath}" arguments="{model: element}" /></f:for><form:plainMail indent="-4"/></f:then><f:else><f:for each="{model.childElements}" as="element"><f:render partial="{element.partialPath}" arguments="{model: element}" /></f:for></f:else></f:if></f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/ContainerElements/Fieldset.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/ContainerElements/Fieldset.html
deleted file mode 100644
index 7bfa2832b075d4dd7698cf6106795b656afa3622..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/ContainerElements/Fieldset.html
+++ /dev/null
@@ -1 +0,0 @@
-{namespace form=TYPO3\CMS\Form\ViewHelpers}<f:if condition="{model.childElements.0}"><f:if condition="{model.showElement}"><f:then><form:plainMail labelContent="{model}" newLineAfterLabel="1" indent="4" /><f:for each="{model.childElements}" as="element"><f:render partial="{element.partialPath}" arguments="{model: element}" /></f:for><form:plainMail indent="-4"/></f:then><f:else><f:for each="{model.childElements}" as="element"><f:render partial="{element.partialPath}" arguments="{model: element}" /></f:for></f:else></f:if></f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/ContainerElements/Form.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/ContainerElements/Form.html
deleted file mode 100644
index 4a71b60e7da3d570e2eb8a9fb064f1f9ea5580b8..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/ContainerElements/Form.html
+++ /dev/null
@@ -1,2 +0,0 @@
-{namespace form=TYPO3\CMS\Form\ViewHelpers}
-<form:plainMail content="{model}" /><f:for each="{model.childElements}" as="element"><f:render partial="{element.partialPath}" arguments="{model: element}" /></f:for>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/ContainerElements/Radiogroup.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/ContainerElements/Radiogroup.html
deleted file mode 100644
index 2a2a5e64fb17797eee1e359f449e3670ac9e26f1..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/ContainerElements/Radiogroup.html
+++ /dev/null
@@ -1 +0,0 @@
-{namespace form=TYPO3\CMS\Form\ViewHelpers}<f:if condition="{model.additionalArguments.atLeastOneCheckedChildElement}"><f:if condition="{model.showElement}"><f:then><form:plainMail labelContent="{model}" newLineAfterLabel="1" indent="4" /><f:for each="{model.childElements}" as="element"><f:render partial="{element.partialPath}" arguments="{model: element}" /></f:for><form:plainMail indent="-4"/></f:then><f:else><f:for each="{model.childElements}" as="element"><f:render partial="{element.partialPath}" arguments="{model: element}" /></f:for></f:else></f:if></f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Button.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Button.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/ButtonTag.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/ButtonTag.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Checkbox.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Checkbox.html
deleted file mode 100644
index 29119c77277c64a618eddbfcc49bed4b0b8233f6..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Checkbox.html
+++ /dev/null
@@ -1 +0,0 @@
-{namespace form=TYPO3\CMS\Form\ViewHelpers}<f:if condition="{model.showElement}"><f:if condition="{model.additionalArguments.checked} == 'checked'"><form:plainMail labelContent="{model}" content="{model.additionalArguments.value}" /></f:if></f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/ContentElement.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/ContentElement.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Header.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Header.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Hidden.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Hidden.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Imagebutton.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Imagebutton.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Input.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Input.html
deleted file mode 100644
index 76676300102b1071cea96043bf5c6d03bb04203e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Input.html
+++ /dev/null
@@ -1 +0,0 @@
-{namespace form=TYPO3\CMS\Form\ViewHelpers}<f:if condition="{model.showElement}"><form:plainMail labelContent="{model}" content="{model}" /></f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/InputTypeButton.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/InputTypeButton.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Password.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Password.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Radio.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Radio.html
deleted file mode 100644
index 73e09419f92288838cb3ba3663ed9c67b0feafe8..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Radio.html
+++ /dev/null
@@ -1,2 +0,0 @@
-{namespace form=TYPO3\CMS\Form\ViewHelpers}<f:if condition="{model.showElement}"><f:if condition="{model.additionalArguments.checked} == 'checked'"><form:plainMail labelContent="{model}" content="{model.additionalArguments.value}" />
-</f:if></f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Reset.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Reset.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Select.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Select.html
deleted file mode 100644
index 122c8666ff2045bd88639451c9e6d38dd00433ab..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Select.html
+++ /dev/null
@@ -1,3 +0,0 @@
-{namespace form=TYPO3\CMS\Form\ViewHelpers}<f:if condition="{model.showElement}"><form:plainMail labelContent="{model}" newLineAfterLabel="1" indent="4" /><f:for each="{form:aggregateSelectOptions(model:model)}" as="option"><f:if condition="{option.options}"><f:then><f:for each="{option.options}" as="optgroupOption"><f:if condition="{optgroupOption.selected}"><form:plainMail content="{optgroupOption.label}" />
-</f:if></f:for></f:then><f:else><f:if condition="{option.selected}"><form:plainMail content="{option.label}" />
-</f:if></f:else></f:if></f:for><form:plainMail indent="-4"/></f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Submit.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Submit.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Textarea.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Textarea.html
deleted file mode 100644
index 5c6ea67aaed547d94866503eaf67023e5ab42dd5..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Textarea.html
+++ /dev/null
@@ -1 +0,0 @@
-{namespace form=TYPO3\CMS\Form\ViewHelpers}<f:if condition="{model.showElement}"><form:plainMail labelContent="{model}" content="{model.additionalArguments.text}" newLineAfterLabel="1" indent="4" /><form:plainMail indent="-4" /></f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Textblock.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Textblock.html
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Textfield.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Textfield.html
deleted file mode 100644
index 76676300102b1071cea96043bf5c6d03bb04203e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Textfield.html
+++ /dev/null
@@ -1 +0,0 @@
-{namespace form=TYPO3\CMS\Form\ViewHelpers}<f:if condition="{model.showElement}"><form:plainMail labelContent="{model}" content="{model}" /></f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Upload.html b/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Upload.html
deleted file mode 100644
index bb9573121a7a5b43ff3185906705a72d9c146cbb..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/PostProcessor/Mail/Plain/FlatElements/Upload.html
+++ /dev/null
@@ -1,2 +0,0 @@
-{namespace form=TYPO3\CMS\Form\ViewHelpers}<f:if condition="{model.showElement}"><form:plainMail labelContent="{model}" newLineAfterLabel="1" indent="4" /><f:for each="{model.additionalArguments.uploadedFiles}" as="uploadedFile"><form:plainMail content="{uploadedFile.name}" />
-</f:for><form:plainMail indent="-4"/></f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/AdditionalElements/ErrorValidationMessage.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/AdditionalElements/ErrorValidationMessage.html
deleted file mode 100644
index 891c7c7d1e200f9e621f6b8d2c392e3fdbaaf203..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/AdditionalElements/ErrorValidationMessage.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<f:if condition="{model.validationErrorMessages}">
-    <strong><f:for each="{model.validationErrorMessages}" as="errorValidationMessage" iteration="iterator">{errorValidationMessage}<f:if condition="{iterator.isLast}"><f:else> - </f:else></f:if></f:for></strong>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/AdditionalElements/Label.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/AdditionalElements/Label.html
deleted file mode 100644
index b4840a4b4892a6fc9f1a260365d280bf93d973d4..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/AdditionalElements/Label.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<label for="{model.additionalArguments.id}">
-    {model.additionalArguments.label}
-    {f:render(partial: '{themeName}/Show/AdditionalElements/MandatoryValidationMessage', arguments: {model: model, themeName: themeName})}
-    {f:render(partial: '{themeName}/Show/AdditionalElements/ErrorValidationMessage', arguments: {model: model, themeName: themeName})}
-</label>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/AdditionalElements/Legend.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/AdditionalElements/Legend.html
deleted file mode 100644
index 7ec127594293f642f804ba39e242301985977148..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/AdditionalElements/Legend.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<f:if condition="{model.additionalArguments.legend}">
-    <legend>
-        {model.additionalArguments.legend}
-        {f:render(partial: '{themeName}/Show/AdditionalElements/MandatoryValidationMessage', arguments: {model: model, themeName: themeName})}
-        {f:render(partial: '{themeName}/Show/AdditionalElements/ErrorValidationMessage', arguments: {model: model, themeName: themeName})}
-    </legend>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/AdditionalElements/MandatoryValidationMessage.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/AdditionalElements/MandatoryValidationMessage.html
deleted file mode 100644
index 4b38cea54a68b36b53465f9e65afc1fae0326d99..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/AdditionalElements/MandatoryValidationMessage.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<f:if condition="{model.mandatoryValidationMessages}">
-    <em><f:for each="{model.mandatoryValidationMessages}" as="mandatoryValidationMessage" iteration="iterator">{mandatoryValidationMessage}<f:if condition="{iterator.isLast}"><f:else> - </f:else></f:if></f:for></em>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/ContainerElements/Checkboxgroup.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/ContainerElements/Checkboxgroup.html
deleted file mode 100644
index fea70dee3ae712f1493245f9c955c51c3611d433..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/ContainerElements/Checkboxgroup.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<f:if condition="{model.showElement}">
-	<f:then>
-		<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-			<fieldset
-			<f:for each="{model.htmlAttributes}" as="htmAttributeValue" key="htmAttributeKey">
-				{htmAttributeKey}="{htmAttributeValue}"
-			</f:for>
-			>
-				{f:render(partial: '{themeName}/Show/AdditionalElements/Legend', arguments: {model: model, themeName: themeName})}
-				<ol>
-					<f:for each="{model.childElements}" as="element">
-						<f:render partial="{themeName}/Show/{element.partialPath}" arguments="{model: element, themeName: themeName}" />
-					</f:for>
-				</ol>
-			</fieldset>
-		</li>
-	</f:then>
-	<f:else>
-		<f:for each="{model.childElements}" as="element">
-			<f:render partial="{themeName}/Show/{element.partialPath}" arguments="{model: element, themeName: themeName}" />
-		</f:for>
-	</f:else>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/ContainerElements/Fieldset.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/ContainerElements/Fieldset.html
deleted file mode 100644
index 8921d4f5cf80a407ba7a6130456bbf0d8d9e0072..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/ContainerElements/Fieldset.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<f:if condition="{model.showElement}">
-	<f:then>
-		<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-			<fieldset
-			<f:for each="{model.htmlAttributes}" as="htmAttributeValue" key="htmAttributeKey">
-				{htmAttributeKey}="{htmAttributeValue}"
-			</f:for>
-			>
-				<f:if condition="{model.additionalArguments.legend}">
-					<legend>{model.additionalArguments.legend}</legend>
-				</f:if>
-				<ol>
-					<f:for each="{model.childElements}" as="element">
-						<f:render partial="{themeName}/Show/{element.partialPath}" arguments="{model: element, themeName: themeName}" />
-					</f:for>
-				</ol>
-			</fieldset>
-		</li>
-	</f:then>
-	<f:else>
-		<f:for each="{model.childElements}" as="element">
-			<f:render partial="{themeName}/Show/{element.partialPath}" arguments="{model: element, themeName: themeName}" />
-		</f:for>
-	</f:else>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/ContainerElements/Form.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/ContainerElements/Form.html
deleted file mode 100644
index fff6fb537549b427336b8d456fba0ea5df11ec3a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/ContainerElements/Form.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<f:form
-	class="{model.additionalArguments.class}"
-	dir="{model.additionalArguments.dir}"
-	id="{model.additionalArguments.id}"
-	lang="{model.additionalArguments.lang}"
-	style="{model.additionalArguments.style}"
-	title="{model.additionalArguments.title}"
-	accesskey="{model.additionalArguments.accesskey}"
-	tabindex="{model.additionalArguments.tabindex}"
-	onclick="{model.additionalArguments.onclick}"
-
-	enctype="{model.additionalArguments.enctype}"
-	method="{model.additionalArguments.method}"
-	name="{model.additionalArguments.name}"
-	onreset="{model.additionalArguments.onreset}"
-	onsubmit="{model.additionalArguments.onsubmit}"
-
-	absolute="{model.additionalArguments.absolute}"
-	action="{model.additionalArguments.action}"
-	actionUri="{model.additionalArguments.actionUri}"
-	addQueryString="{model.additionalArguments.addQueryString}"
-	additionalAttributes="{model.htmlAttributes}"
-	additionalParams="{model.additionalArguments.additionalParams}"
-	arguments="{model.additionalArguments.arguments}"
-	argumentsToBeExcludedFromQueryString="{model.additionalArguments.argumentsToBeExcludedFromQueryString}"
-	controller="{model.additionalArguments.controller}"
-	extensionName="{model.additionalArguments.extensionName}"
-
-	format="{f:if(condition:'{model.additionalArguments.format}',then:'{model.additionalArguments.format}')}"
-	hiddenFieldClassName="{model.additionalArguments.hiddenFieldClassName}"
-
-	object="{model}"
-
-	pageType="{model.additionalArguments.pageType}"
-	pageUid="{model.additionalArguments.pageUid}"
-	pluginName="{model.additionalArguments.pluginName}"
-	section="{model.additionalArguments.section}">
-
-	<ol>
-		<f:for each="{model.childElements}" as="element">
-			<f:render partial="{themeName}/Show/{element.partialPath}" arguments="{model: element, themeName: themeName}" />
-		</f:for>
-	</ol>
-</f:form>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/ContainerElements/Radiogroup.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/ContainerElements/Radiogroup.html
deleted file mode 100644
index 562311e5c2e97c7c6302b047cb5dda827d147586..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/ContainerElements/Radiogroup.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<f:if condition="{model.showElement}">
-	<f:then>
-		<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-			<fieldset
-				<f:for each="{model.htmlAttributes}" as="htmAttributeValue" key="htmAttributeKey">
-					{htmAttributeKey}="{htmAttributeValue}"
-				</f:for>
-			>
-				{f:render(partial: '{themeName}/Show/AdditionalElements/Legend', arguments: {model: model, themeName: themeName})}
-				<ol>
-					<f:for each="{model.childElements}" as="element">
-						<f:render partial="{themeName}/Show/{element.partialPath}" arguments="{model: element, themeName: themeName}" />
-					</f:for>
-				</ol>
-			</fieldset>
-		</li>
-	</f:then>
-	<f:else>
-		<f:for each="{model.childElements}" as="element">
-			<f:render partial="{themeName}/Show/{element.partialPath}" arguments="{model: element, themeName: themeName}" />
-		</f:for>
-	</f:else>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Button.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Button.html
deleted file mode 100644
index c70ea7104167a9ba22619368e9460b9e7ef8283a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Button.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Show/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-
-		<f:form.button
-			class="{model.additionalArguments.class}"
-			dir="{model.additionalArguments.dir}"
-			id="{model.additionalArguments.id}"
-			lang="{model.additionalArguments.lang}"
-			style="{model.additionalArguments.style}"
-			title="{model.additionalArguments.title}"
-			accesskey="{model.additionalArguments.accesskey}"
-			tabindex="{model.additionalArguments.tabindex}"
-			onclick="{model.additionalArguments.onclick}"
-
-			name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-			value="{model.additionalArguments.value}"
-
-			autofocus="{model.additionalArguments.autofocus}"
-			type="{model.additionalArguments.type}"
-
-			additionalAttributes="{model.htmlAttributes}"
-		>{model.additionalArguments.value}</f:form.button>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/ButtonTag.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/ButtonTag.html
deleted file mode 100644
index 7d3735a748c76f25691d27dfce63f361ba1445eb..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/ButtonTag.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Show/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-
-		<f:form.button
-			class="{model.additionalArguments.class}"
-			dir="{model.additionalArguments.dir}"
-			id="{model.additionalArguments.id}"
-			lang="{model.additionalArguments.lang}"
-			style="{model.additionalArguments.style}"
-			title="{model.additionalArguments.title}"
-			accesskey="{model.additionalArguments.accesskey}"
-			tabindex="{model.additionalArguments.tabindex}"
-			onclick="{model.additionalArguments.onclick}"
-
-			name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-			value="{model.additionalArguments.value}"
-
-			autofocus="{model.additionalArguments.autofocus}"
-			type="{model.additionalArguments.type}"
-		>{model.attributes.value.value}</f:form.button>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Checkbox.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Checkbox.html
deleted file mode 100644
index 2782e80dff48760b8333cbf67a073db3ef2a7d97..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Checkbox.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Show/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-
-		<f:if condition="{model.additionalArguments.multiple}">
-			<f:then>
-				<f:form.checkbox
-					class="{model.additionalArguments.class}"
-					dir="{model.additionalArguments.dir}"
-					id="{model.additionalArguments.id}"
-					lang="{model.additionalArguments.lang}"
-					style="{model.additionalArguments.style}"
-					title="{model.additionalArguments.title}"
-					accesskey="{model.additionalArguments.accesskey}"
-					tabindex="{model.additionalArguments.tabindex}"
-					onclick="{model.additionalArguments.onclick}"
-
-					name="{model.additionalArguments.prefix}[{model.additionalArguments.name}][{model.name}]"
-					value="<f:if condition='{model.additionalArguments.value}'><f:then>{model.additionalArguments.value}</f:then><f:else>{model.additionalArguments.name}-{model.elementCounter}</f:else></f:if>"
-
-					checked="{model.additionalArguments.checked}"
-
-					errorClass="{model.additionalAttributes.errorClass}"
-					additionalAttributes="{model.htmlAttributes}"
-				/>
-			</f:then>
-			<f:else>
-				<f:form.checkbox
-					class="{model.additionalArguments.class}"
-					dir="{model.additionalArguments.dir}"
-					id="{model.additionalArguments.id}"
-					lang="{model.additionalArguments.lang}"
-					style="{model.additionalArguments.style}"
-					title="{model.additionalArguments.title}"
-					accesskey="{model.additionalArguments.accesskey}"
-					tabindex="{model.additionalArguments.tabindex}"
-					onclick="{model.additionalArguments.onclick}"
-
-					name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-					value="<f:if condition='{model.additionalArguments.value}'><f:then>{model.additionalArguments.value}</f:then><f:else>{model.additionalArguments.name}-{model.elementCounter}</f:else></f:if>"
-
-					checked="{model.additionalArguments.checked}"
-
-					errorClass="{model.additionalAttributes.errorClass}"
-					additionalAttributes="{model.htmlAttributes}"
-				/>
-			</f:else>
-		</f:if>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/ContentElement.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/ContentElement.html
deleted file mode 100644
index 16f128849bec594524eca4d44cbe9a8a1ad4fe75..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/ContentElement.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		<f:format.raw>{model.additionalArguments.content}</f:format.raw>
-	</li>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Header.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Header.html
deleted file mode 100644
index 477d4985334be87e8e64668dfbe28520a0c9582b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Header.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		<f:format.raw><{model.additionalArguments.headingSize}>{model.additionalArguments.content}</{model.additionalArguments.headingSize}></f:format.raw>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Hidden.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Hidden.html
deleted file mode 100644
index 6f3c765a6eb97a9a4fbbcc9229800899a208fdec..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Hidden.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-	<f:form.hidden
-		class="{model.additionalArguments.class}"
-		dir="{model.additionalArguments.dir}"
-		id="{model.additionalArguments.id}"
-		lang="{model.additionalArguments.lang}"
-		style="{model.additionalArguments.style}"
-		title="{model.additionalArguments.title}"
-		accesskey="{model.additionalArguments.accesskey}"
-		tabindex="{model.additionalArguments.tabindex}"
-		onclick="{model.additionalArguments.onclick}"
-
-		name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-		value="{model.additionalArguments.value}"
-
-		additionalAttributes="{model.htmlAttributes}"
-	/>
-</li>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Imagebutton.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Imagebutton.html
deleted file mode 100644
index c60c4646aff2e223e1c96501fee6673604e65c4d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Imagebutton.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Show/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-
-		<f:form.textfield
-			class="{model.additionalArguments.class}"
-			dir="{model.additionalArguments.dir}"
-			id="{model.additionalArguments.id}"
-			lang="{model.additionalArguments.lang}"
-			style="{model.additionalArguments.style}"
-			title="{model.additionalArguments.title}"
-			accesskey="{model.additionalArguments.accesskey}"
-			tabindex="{model.additionalArguments.tabindex}"
-			onclick="{model.additionalArguments.onclick}"
-
-			name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-			value="{model.additionalArguments.value}"
-
-			autofocus="{model.additionalArguments.autofocus}"
-			maxlength="{model.additionalArguments.maxlength}"
-			size="{model.additionalArguments.size}"
-			placeholder="{model.additionalArguments.placeholder}"
-			pattern="{model.additionalArguments.pattern}"
-			required="{model.additionalArguments.required}"
-			type="{model.additionalArguments.type}"
-
-			errorClass="{model.additionalArguments.errorClass}"
-			additionalAttributes="{model.htmlAttributes}"
-		/>
-	</li>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Input.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Input.html
deleted file mode 100644
index c60c4646aff2e223e1c96501fee6673604e65c4d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Input.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Show/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-
-		<f:form.textfield
-			class="{model.additionalArguments.class}"
-			dir="{model.additionalArguments.dir}"
-			id="{model.additionalArguments.id}"
-			lang="{model.additionalArguments.lang}"
-			style="{model.additionalArguments.style}"
-			title="{model.additionalArguments.title}"
-			accesskey="{model.additionalArguments.accesskey}"
-			tabindex="{model.additionalArguments.tabindex}"
-			onclick="{model.additionalArguments.onclick}"
-
-			name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-			value="{model.additionalArguments.value}"
-
-			autofocus="{model.additionalArguments.autofocus}"
-			maxlength="{model.additionalArguments.maxlength}"
-			size="{model.additionalArguments.size}"
-			placeholder="{model.additionalArguments.placeholder}"
-			pattern="{model.additionalArguments.pattern}"
-			required="{model.additionalArguments.required}"
-			type="{model.additionalArguments.type}"
-
-			errorClass="{model.additionalArguments.errorClass}"
-			additionalAttributes="{model.htmlAttributes}"
-		/>
-	</li>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/InputTypeButton.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/InputTypeButton.html
deleted file mode 100644
index ec954789f047a9d47f9104e749cbd4632065d0c1..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/InputTypeButton.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Show/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-
-		<f:form.textfield
-			class="{model.additionalArguments.class}"
-			dir="{model.additionalArguments.dir}"
-			id="{model.additionalArguments.id}"
-			lang="{model.additionalArguments.lang}"
-			style="{model.additionalArguments.style}"
-			title="{model.additionalArguments.title}"
-			accesskey="{model.additionalArguments.accesskey}"
-			tabindex="{model.additionalArguments.tabindex}"
-			onclick="{model.additionalArguments.onclick}"
-
-			name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-			value="{model.additionalArguments.value}"
-
-			autofocus="{model.additionalArguments.autofocus}"
-			maxlength="{model.additionalArguments.maxlength}"
-			size="{model.additionalArguments.size}"
-			placeholder="{model.additionalArguments.placeholder}"
-			pattern="{model.additionalArguments.pattern}"
-			required="{model.additionalArguments.required}"
-			type="{model.additionalArguments.type}"
-
-			errorClass="{model.additionalArguments.errorClass}"
-			additionalAttributes="{model.htmlAttributes}"
-		/>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Password.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Password.html
deleted file mode 100644
index f384b7acae12ee304f8628f1ac7be83262056922..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Password.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Show/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-
-		<f:form.password
-			class="{model.additionalArguments.class}"
-			dir="{model.additionalArguments.dir}"
-			id="{model.additionalArguments.id}"
-			lang="{model.additionalArguments.lang}"
-			style="{model.additionalArguments.style}"
-			title="{model.additionalArguments.title}"
-			accesskey="{model.additionalArguments.accesskey}"
-			tabindex="{model.additionalArguments.tabindex}"
-			onclick="{model.additionalArguments.onclick}"
-
-			name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-			value="{model.additionalArguments.value}"
-
-			maxlength="{model.additionalArguments.maxlength}"
-			size="{model.additionalArguments.size}"
-
-			errorClass="{model.additionalArguments.errorClass}"
-			additionalAttributes="{model.htmlAttributes}"
-		/>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Radio.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Radio.html
deleted file mode 100644
index 1b1e5167ac9bfe17673402257315023328e52b35..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Radio.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Show/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-
-		<f:form.radio
-			class="{model.additionalArguments.class}"
-			dir="{model.additionalArguments.dir}"
-			id="{model.additionalArguments.id}"
-			lang="{model.additionalArguments.lang}"
-			style="{model.additionalArguments.style}"
-			title="{model.additionalArguments.title}"
-			accesskey="{model.additionalArguments.accesskey}"
-			tabindex="{model.additionalArguments.tabindex}"
-			onclick="{model.additionalArguments.onclick}"
-
-			name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-			value="<f:if condition='{model.additionalArguments.value}'><f:then>{model.additionalArguments.value}</f:then><f:else>{model.additionalArguments.name}-{model.elementCounter}</f:else></f:if>"
-
-			checked="{model.additionalArguments.checked}"
-
-			errorClass="{model.additionalArguments.errorClass}"
-			additionalAttributes="{model.htmlAttributes}"
-		/>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Reset.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Reset.html
deleted file mode 100644
index ec954789f047a9d47f9104e749cbd4632065d0c1..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Reset.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Show/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-
-		<f:form.textfield
-			class="{model.additionalArguments.class}"
-			dir="{model.additionalArguments.dir}"
-			id="{model.additionalArguments.id}"
-			lang="{model.additionalArguments.lang}"
-			style="{model.additionalArguments.style}"
-			title="{model.additionalArguments.title}"
-			accesskey="{model.additionalArguments.accesskey}"
-			tabindex="{model.additionalArguments.tabindex}"
-			onclick="{model.additionalArguments.onclick}"
-
-			name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-			value="{model.additionalArguments.value}"
-
-			autofocus="{model.additionalArguments.autofocus}"
-			maxlength="{model.additionalArguments.maxlength}"
-			size="{model.additionalArguments.size}"
-			placeholder="{model.additionalArguments.placeholder}"
-			pattern="{model.additionalArguments.pattern}"
-			required="{model.additionalArguments.required}"
-			type="{model.additionalArguments.type}"
-
-			errorClass="{model.additionalArguments.errorClass}"
-			additionalAttributes="{model.htmlAttributes}"
-		/>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Select.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Select.html
deleted file mode 100644
index 7270eb7eb0f27f19f736116437ae44c66630b3d5..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Select.html
+++ /dev/null
@@ -1,36 +0,0 @@
-{namespace form=TYPO3\CMS\Form\ViewHelpers}
-
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Show/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-
-		<form:select
-			class="{model.additionalArguments.class}"
-			dir="{model.additionalArguments.dir}"
-			id="{model.additionalArguments.id}"
-			lang="{model.additionalArguments.lang}"
-			style="{model.additionalArguments.style}"
-			title="{model.additionalArguments.title}"
-			accesskey="{model.additionalArguments.accesskey}"
-			tabindex="{model.additionalArguments.tabindex}"
-			onclick="{model.additionalArguments.onclick}"
-
-			name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-			value="{form:aggregateSelectOptions(model:model, returnSelectedValues: 1)}"
-
-			multiple="{model.additionalArguments.multiple}"
-			size="{model.additionalArguments.size}"
-
-			optionLabelField="label"
-			optionValueField="value"
-			options="{form:aggregateSelectOptions(model:model)}"
-			prependOptionLabel="{model.additionalArguments.prependOptionLabel}"
-			prependOptionValue="{model.additionalArguments.prependOptionValue}"
-			selectAllByDefault="{model.additionalArguments.selectAllByDefault}"
-			sortByOptionLabel="{model.additionalArguments.sortByOptionLabel}"
-
-			errorClass="{model.additionalArguments.errorClass}"
-			additionalAttributes="{model.htmlAttributes}"
-		/>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Submit.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Submit.html
deleted file mode 100644
index cf6c9d20d21c008d919dc47cd319dd8962eea548..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Submit.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Show/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-
-		<f:form.submit
-			additionalAttributes="{model.htmlAttributes}"
-			dir="{model.additionalArguments.dir}"
-			id="{model.additionalArguments.id}"
-			lang="{model.additionalArguments.lang}"
-			style="{model.additionalArguments.style}"
-			title="{model.additionalArguments.title}"
-			accesskey="{model.additionalArguments.accesskey}"
-			tabindex="{model.additionalArguments.tabindex}"
-			onclick="{model.additionalArguments.onclick}"
-
-			name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-			value="{model.additionalArguments.value}"
-		/>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Textarea.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Textarea.html
deleted file mode 100644
index 61ff619ca6a15f263d43c4ef957743a13a7b562d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Textarea.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Show/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-
-		<f:form.textarea
-			class="{model.additionalArguments.class}"
-			dir="{model.additionalArguments.dir}"
-			id="{model.additionalArguments.id}"
-			lang="{model.additionalArguments.lang}"
-			style="{model.additionalArguments.style}"
-			title="{model.additionalArguments.title}"
-			accesskey="{model.additionalArguments.accesskey}"
-			tabindex="{model.additionalArguments.tabindex}"
-			onclick="{model.additionalArguments.onclick}"
-
-			name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-			value="{model.additionalArguments.text}"
-
-			autofocus="{model.additionalArguments.autofocus}"
-			rows="{model.additionalArguments.rows}"
-			cols="{model.additionalArguments.cols}"
-			placeholder="{model.additionalArguments.placeholder}"
-
-			errorClass="{model.additionalArguments.errorClass}"
-			additionalAttributes="{model.htmlAttributes}"
-		/>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Textblock.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Textblock.html
deleted file mode 100644
index 625809e71b66c6ed010cf4d5bfc90e5da1c3e60c..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Textblock.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		<f:format.raw>{model.additionalArguments.text}</f:format.raw>
-	</li>
-</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Textfield.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Textfield.html
deleted file mode 100644
index 14c1d62aefb93c46fe50d2c5273447f1bb4bc904..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Textfield.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Show/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-
-		<f:form.textfield
-			class="{model.additionalArguments.class}"
-			dir="{model.additionalArguments.dir}"
-			id="{model.additionalArguments.id}"
-			lang="{model.additionalArguments.lang}"
-			style="{model.additionalArguments.style}"
-			title="{model.additionalArguments.title}"
-			accesskey="{model.additionalArguments.accesskey}"
-			tabindex="{model.additionalArguments.tabindex}"
-			onclick="{model.additionalArguments.onclick}"
-
-			value="{model.additionalArguments.value}"
-			name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-
-			autofocus="{model.additionalArguments.autofocus}"
-			maxlength="{model.additionalArguments.maxlength}"
-			size="{model.additionalArguments.size}"
-			placeholder="{model.additionalArguments.placeholder}"
-			pattern="{model.additionalArguments.pattern}"
-			required="{model.additionalArguments.required}"
-			type="{model.additionalArguments.type}"
-
-			errorClass="{model.additionalArguments.errorClass}"
-			additionalAttributes="{model.htmlAttributes}"
-		/>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Upload.html b/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Upload.html
deleted file mode 100644
index 9f858309738265c1ea0e4fc3d9d8b436289daa90..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Partials/Default/Show/FlatElements/Upload.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<f:if condition="{model.showElement}">
-	<li class="csc-form-{model.elementCounter} csc-form-element csc-form-element-{model.elementTypeLowerCase}">
-		{f:render(partial: '{themeName}/Show/AdditionalElements/Label', arguments: {model: model, themeName: themeName})}
-
-		<f:form.upload
-			class="{model.additionalArguments.class}"
-			dir="{model.additionalArguments.dir}"
-			id="{model.additionalArguments.id}"
-			lang="{model.additionalArguments.lang}"
-			style="{model.additionalArguments.style}"
-			title="{model.additionalArguments.title}"
-			accesskey="{model.additionalArguments.accesskey}"
-			tabindex="{model.additionalArguments.tabindex}"
-			onclick="{model.additionalArguments.onclick}"
-
-			name="{model.additionalArguments.prefix}[{model.additionalArguments.name}]"
-			value="{model.additionalArguments.value}"
-
-			multiple="{model.additionalArguments.multiple}"
-
-			errorClass="{model.additionalArguments.errorClass}"
-			additionalAttributes="{model.htmlAttributes}"
-		/>
-	</li>
-</f:if>
diff --git a/typo3/sysext/form/Resources/Private/Templates/Frontend/AfterProcess.html b/typo3/sysext/form/Resources/Private/Templates/Frontend/AfterProcess.html
deleted file mode 100644
index 0592e2b79c6e40045f38abb7c5d1b15812987be0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Templates/Frontend/AfterProcess.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<f:layout name="Default" />
-
-<f:section name="main">
-	<f:format.raw>{postProcessorContent}</f:format.raw>
-</f:section>
diff --git a/typo3/sysext/form/Resources/Private/Templates/Frontend/Confirmation.html b/typo3/sysext/form/Resources/Private/Templates/Frontend/Confirmation.html
deleted file mode 100644
index 0fbefd5917f87596224c3fd4c8b49cb8963d6efa..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Templates/Frontend/Confirmation.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<f:layout name="Default" />
-
-<f:section name="main">
-	<f:format.raw>{message}</f:format.raw>
-	<f:render partial="{model.themeName}/Confirmation/ContainerElements/Form" arguments="{model: model, themeName: model.themeName}" />
-</f:section>
diff --git a/typo3/sysext/form/Resources/Private/Templates/Frontend/Show.html b/typo3/sysext/form/Resources/Private/Templates/Frontend/Show.html
deleted file mode 100644
index 31ed85e898be64301bc36a00b8f713bb4ca37adc..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Templates/Frontend/Show.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<f:layout name="Default" />
-
-<f:section name="main">
-	<f:render partial="{model.themeName}/Show/ContainerElements/Form" arguments="{model: model, themeName: model.themeName}" />
-</f:section>
diff --git a/typo3/sysext/form/Resources/Private/Templates/PostProcessor/Mail/Default/Html.html b/typo3/sysext/form/Resources/Private/Templates/PostProcessor/Mail/Default/Html.html
deleted file mode 100644
index e50cfa8afb0f8c409ba09d8ea59c11c89caab44d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Templates/PostProcessor/Mail/Default/Html.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<f:layout name="Default" />
-
-<f:section name="main">
-	<f:render partial="ContainerElements/Form" arguments="{model: model}" />
-</f:section>
diff --git a/typo3/sysext/form/Resources/Private/Templates/PostProcessor/Mail/Default/Plain.html b/typo3/sysext/form/Resources/Private/Templates/PostProcessor/Mail/Default/Plain.html
deleted file mode 100644
index 66119ca554d0d34e7ac78348ac38560a38c967a2..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Templates/PostProcessor/Mail/Default/Plain.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<f:layout name="Default" />
-
-<f:section name="main">
-	<f:render partial="ContainerElements/Form" arguments="{model: model, themeName: model.themeName}" />
-</f:section>
diff --git a/typo3/sysext/form/Resources/Private/Templates/Wizard.html b/typo3/sysext/form/Resources/Private/Templates/Wizard.html
deleted file mode 100644
index f498835def3a6a079b037d0bbac70f1a15a9e51f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Private/Templates/Wizard.html
+++ /dev/null
@@ -1,71 +0,0 @@
-<!-- ###FULLDOC### begin -->
-<div class="typo3-fullDoc">
-	<div id="typo3-docheader">
-		<div class="typo3-docheader-functions">
-			<div class="left">###CSH###</div>
-			<div class="right"></div>
-		</div>
-		<div class="typo3-docheader-buttons">
-			<div class="left">###BUTTONLIST_LEFT###</div>
-			<div class="right">###BUTTONLIST_RIGHT###</div>
-		</div>
-	</div>
-
-	<div id="typo3-docbody">
-		<div id="typo3-inner-docbody">
-			###CONTENT###
-		</div>
-	</div>
-</div>
-<!-- ###FULLDOC### end -->
-
-<!-- Grouping the icons on top -->
-
-<!-- ###BUTTON_GROUP_WRAP### -->
-	<div class="buttongroup">###BUTTONS###</div>
-<!-- ###BUTTON_GROUP_WRAP### -->
-
-<!-- ###BUTTON_GROUPS_LEFT### -->
-<!-- ###BUTTON_GROUP1### -->###CLOSE###<!-- ###BUTTON_GROUP1### -->
-<!-- ###BUTTON_GROUP2### -->###SAVE######SAVE_CLOSE###<!-- ###BUTTON_GROUP2### -->
-<!-- ###BUTTON_GROUPS_LEFT### -->
-
-<!-- ###BUTTON_GROUPS_RIGHT### -->
-<!-- ###BUTTON_GROUP1### -->###RELOAD###<!-- ###BUTTON_GROUP1### -->
-<!-- ###BUTTON_GROUPS_RIGHT### -->
-<!-- ###FULLDOC### begin -->
-<div class="typo3-fullDoc">
-	<!-- Page header with buttons, path details and csh -->
-	<div id="typo3-docheader">
-		<div class="typo3-docheader-functions">
-			<div class="left">###CSH###</div>
-			<div class="right"></div>
-		</div>
-		<div class="typo3-docheader-buttons">
-			<div class="left">###BUTTONLIST_LEFT###</div>
-			<div class="right">###BUTTONLIST_RIGHT###</div>
-		</div>
-	</div>
-	<!-- Content of module, for instance listing, info or editing -->
-	<div id="typo3-docbody">
-		<div id="typo3-inner-docbody">
-			###CONTENT###
-		</div>
-	</div>
-</div>
-<!-- ###FULLDOC### end -->
-
-<!-- Grouping the icons on top -->
-
-<!-- ###BUTTON_GROUP_WRAP### -->
-	<div class="buttongroup">###BUTTONS###</div>
-<!-- ###BUTTON_GROUP_WRAP### -->
-
-<!-- ###BUTTON_GROUPS_LEFT### -->
-<!-- ###BUTTON_GROUP1### -->###CLOSE###<!-- ###BUTTON_GROUP1### -->
-<!-- ###BUTTON_GROUP2### -->###SAVE######SAVE_CLOSE###<!-- ###BUTTON_GROUP2### -->
-<!-- ###BUTTON_GROUPS_LEFT### -->
-
-<!-- ###BUTTON_GROUPS_RIGHT### -->
-<!-- ###BUTTON_GROUP1### -->###RELOAD###<!-- ###BUTTON_GROUP1### -->
-<!-- ###BUTTON_GROUPS_RIGHT### -->
diff --git a/typo3/sysext/form/Resources/Public/Css/form.css b/typo3/sysext/form/Resources/Public/Css/form.css
index b0f77e2c846261c17fe025326d4b1fb96587ae2e..07ec5253b563a6d2c9a115e97c6f6021feda83b6 100644
--- a/typo3/sysext/form/Resources/Public/Css/form.css
+++ b/typo3/sysext/form/Resources/Public/Css/form.css
@@ -11,576 +11,823 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-.std-em-selector {
-  font-size: 90%;
-  font-style: normal;
+.t3-form-x-component {
+  position: absolute;
+  top: 0;
+  height: 100%;
+  line-height: normal;
+  background: #f5f5f5;
 }
-.std-strong-selector {
-  display: block;
-  font-size: 90%;
-  font-weight: normal;
-  color: #C00;
-}
-.std-li-selector {
-  float: none;
-  width: auto;
-  margin-right: 0;
-  margin-left: 1em;
+.t3-form-x-component a {
+  text-decoration: none;
+}
+.t3-form-x-component ol,
+.t3-form-x-component ul {
+  list-style: none;
+  padding: 0;
 }
-#fake-form {
-  /* style for each form element */
-  /* labels as block, labels displayed above or below the input fields */
+.t3-form-x-component .ui-sortable-placeholder {
+  outline-offset: -1px !important;
 }
-#fake-form ol {
-  padding-left: 0 !important;
-  list-style: none !important;
+.t3-form-x-component-inner-wrapper {
+  padding: 1.5em;
 }
-#fake-form li {
+#t3-form-navigation-component {
   overflow: hidden;
-  padding: 0.5em;
-  margin-bottom: 0.5em;
+  left: 0;
 }
-#fake-form li#element-placeholder {
-  padding: 0;
-  margin: 0;
+#t3-form-structure-panel {
+  overflow: auto;
+  padding-top: 65px;
+  height: 100%;
 }
-#fake-form li input + label,
-#fake-form li textarea + label,
-#fake-form li select + label {
-  float: none;
-  width: auto;
-  margin-right: 0;
-  margin-left: 1em;
+#t3-form-structure-panel .icon {
+  z-index: 1;
 }
-#fake-form li textarea + label {
-  vertical-align: top;
+#t3-form-structure-panel #t3-form-navigation-component-tree-root-container,
+#t3-form-structure-panel .tree li > div {
+  border: 1px solid transparent;
+  cursor: pointer;
 }
-#fake-form textarea,
-#fake-form input[type=text] {
-  border: 1px solid #c0c0c0;
+#t3-form-structure-panel .tree .svg-wrapper svg {
+  overflow: visible;
+  position: relative;
+  top: -0.8em;
+  left: 0.6em;
 }
-#fake-form input[type=text] {
-  width: 300px;
-  padding: 3px;
+#t3-form-structure-panel .tree .svg-wrapper path {
+  fill: none;
+  shape-rendering: crispEdges;
+  stroke: #dddddd;
+  stroke-width: 1;
 }
-#fake-form label {
-  display: block;
-  margin-right: 1em;
-  vertical-align: baseline;
+#t3-form-structure-panel .tree li {
+  white-space: nowrap;
 }
-#fake-form label em {
-  font-size: 90%;
-  font-style: normal;
+#t3-form-structure-panel .tree li .icon-actions-pagetree-collapse {
+  margin-right: 0.3em;
 }
-#fake-form label strong {
-  display: block;
-  font-size: 90%;
-  font-weight: normal;
-  color: #C00;
+#t3-form-structure-panel .tree li .icon-actions-pagetree-collapse img {
+  transform: rotate(90deg);
+  transition: transform 0.2s;
 }
-#fake-form .x-checkbox label,
-#fake-form .x-radio label {
-  display: inline-block;
+#t3-form-structure-panel .tree li.mjs-nestedSortable-collapsed > ol {
+  display: none;
 }
-#fake-form legend {
-  border-bottom: 0;
+#t3-form-structure-panel .tree li.mjs-nestedSortable-collapsed .icon-actions-pagetree-collapse img {
+  transform: rotate(0deg);
+  transition: transform 0.2s;
+}
+#t3-form-structure-panel .tree li small {
+  padding-left: 0.5em;
+  font-size: 80%;
+}
+#t3-form-structure-panel .tree .t3-form-icon {
+  margin-right: 0.5em;
+  margin-left: 0.5em;
+}
+#t3-form-structure-panel .tree .t3-form-element-has-children > div .t3-form-icon {
+  margin-left: 0.1em;
+}
+#t3-form-structure-panel .tree .sortable-hover {
+  outline: 1px solid #aaaaaa;
+}
+#t3-form-structure-panel .tree li > div:hover,
+#t3-form-structure-panel .t3-form-form-element-selected,
+#t3-form-structure-panel #t3-form-navigation-component-tree-root-container:hover,
+#t3-form-structure-panel .t3-form-root-element-selected {
+  background-color: #f2f2f2;
+  border-color: #dcdcdc;
+  border-radius: 2px;
+  margin-left: -2em;
+  padding-left: 2em;
+  margin-right: -1.3em;
+}
+#t3-form-structure-panel .tree li > .t3-form-form-element-selected,
+#t3-form-structure-panel .tree li > .t3-form-form-element-selected:hover,
+#t3-form-structure-panel #t3-form-navigation-component-tree-root-container.t3-form-root-element-selected,
+#t3-form-structure-panel #t3-form-navigation-component-tree-root-container.t3-form-root-element-selected:hover {
+  background-color: #fff;
+  border-color: #dcdcdc;
 }
-#fake-form legend em {
-  font-size: 90%;
-  font-style: normal;
+#t3-form-structure-panel .t3-form-x-component-inner-wrapper {
+  padding-top: 2.5em;
 }
-#fake-form legend strong {
-  display: block;
-  font-size: 90%;
-  font-weight: normal;
-  color: #C00;
+.form-group.t3-form-collection-element-remove-button,
+.t3-form-inspector-finishers-editor-removeButton,
+.form-group.t3-form-inspector-validators-editor-removeButton {
+  margin: 0 !important;
+  font-size: 0;
 }
-#fake-form fieldset {
-  position: relative;
+#t3-form-inspector-panels-container {
+  overflow: hidden;
+  right: 0;
+  padding-top: 65px;
+}
+#t3-form-inspector-panels {
+  overflow: auto;
+  height: 100%;
+}
+#t3-form-inspector {
+  padding: 1em 0.5em;
+}
+#t3-form-inspector h2,
+#t3-form-inspector h3,
+#t3-form-inspector h4 {
   margin: 0;
-  padding: 0;
+  padding: 0.1em 0.2em 0.2em 0.5em;
+  border-top: 1px solid #c3c3c3;
+  clear: both;
+  font: inherit;
+  font-weight: bold;
 }
-#fake-form fieldset.submit {
-  border-style: none;
+#t3-form-inspector h2 {
+  padding-bottom: 1em;
+  border: none;
+  border-bottom: 1px solid #c3c3c3;
 }
-#fake-form fieldset.fieldset-horizontal {
-  border-width: 0;
+#t3-form-inspector > h2:first-child {
+  border-top: none;
 }
-#fake-form fieldset.fieldset-horizontal.label-below label {
-  display: block;
-  margin-left: 0;
-  margin-top: 0.2em;
-  font-size: 90%;
-  text-align: left;
-  color: #999999;
+#t3-form-inspector h3 {
+  color: #000;
+  padding-top: 0.3em;
+  border: none;
 }
-#fake-form fieldset.fieldset-horizontal label em {
-  display: inline;
+#t3-form-inspector h4 {
+  padding: 0.8em 3em 0.8em 2.5em;
+  font-weight: 500;
+  background-color: #ddd;
 }
-#fake-form fieldset.fieldset-horizontal ol {
-  padding: 0;
+#t3-form-inspector h4 span[data-template-property="label"] {
+  vertical-align: top;
 }
-#fake-form fieldset.fieldset-horizontal li {
-  float: left;
-  margin-right: 1em;
-  padding: 0;
+#t3-form-inspector .t3-form-remove-element-button {
+  position: absolute;
+  top: 90px;
+  right: 2.5em;
 }
-#fake-form fieldset.fieldset-subgroup {
-  margin-bottom: -2em;
-  border-style: none;
+#t3-form-inspector .t3-form-control-group,
+#t3-form-inspector .t3-form-add-collection-element {
+  margin: 1.5em 0.5em;
+  clear: both;
 }
-#fake-form fieldset.fieldset-subgroup ol {
-  position: relative;
-  top: -1.4em;
-  padding: 0;
+#t3-form-inspector .t3-form-inspector-editor-requiredValidator label {
+  cursor: pointer;
 }
-#fake-form fieldset.fieldset-subgroup li {
-  padding: 0;
+.t3-form-add-collection-element {
+  padding-bottom: 1em;
 }
-#fake-form fieldset.fieldset-subgroup legend {
-  margin-left: 0;
-  padding: 0;
+.t3-form-collection-container {
+  margin-top: -1em;
+  padding: 0.6em;
 }
-#fake-form fieldset.fieldset-subgroup input + label {
-  float: none;
-  width: auto;
-  display: inline;
-  margin: 0 0 0 1em;
+.t3-form-collection-container .ui-sortable-handle {
+  cursor: auto;
 }
-#fake-form legend {
-  font-size: 12px;
-  font-weight: bold;
-  color: #000000;
+.t3-form-collection-container h4 {
+  cursor: move;
 }
-#fake-form legend em {
+.t3-form-collection-container .icon-actions-view-table-expand {
   position: absolute;
+  left: 0.5em;
+}
+.t3-form-collection-container a.collapsed .icon-actions-view-table-expand svg {
+  transform: rotate(0deg);
+  transition: transform 0.2s;
+}
+.t3-form-collection-container a:not(.collapsed) .icon-actions-view-table-expand svg {
+  transform: rotate(90deg);
+  transition: transform 0.2s;
+}
+.t3-form-collection-element {
+  position: relative;
+  margin-bottom: 0.5em;
+  border: 1px solid #c3c3c3;
+  border-top: none;
+  background: #f5f5f5;
 }
-#fake-form legend strong {
+.t3-form-collection-element .t3-form-collection-element-remove-button {
   position: absolute;
-  top: 1.4em;
+  right: 0.5em;
+  top: 0.6em;
 }
-#fake-form .labels-block label {
-  display: block;
-  float: none;
-  margin: 0 0 0.5em;
-  width: auto;
+.property-grid .form-control {
+  min-width: initial;
+  min-width: auto;
+  font-size: 0.9em;
 }
-#fake-form .labels-block input + label,
-#fake-form .labels-block textarea + label {
-  margin: 0.5em 0 0;
+.property-grid .table th {
+  font-size: 0.9em;
 }
-/* labels alignment right */
-#fake-form .labels-alignment-right label,
-#fake-form .labels-alignment-right .fieldset-subgroup legend,
-#fake-form .labels-alignment-right.fieldset-subgroup legend {
-  text-align: right;
+.property-grid .table > tbody > tr {
+  cursor: pointer;
+  background-color: #fafafa;
 }
-#fake-form .labels-block fieldset.fieldset-subgroup,
-#fake-form fieldset.labels-block.fieldset-subgroup {
-  margin-bottom: 0;
+.property-grid .table > tbody > tr:last-child {
+  cursor: auto;
 }
-#fake-form .labels-block .fieldset-subgroup legend,
-#fake-form .labels-block.fieldset-subgroup legend {
-  width: auto;
+.property-grid .table > tbody > tr > td {
+  padding: 0.6em 0.3em;
+  text-align: center;
 }
-#fake-form .labels-block .fieldset-subgroup legend em,
-#fake-form .labels-block.fieldset-subgroup legend em {
-  position: relative;
+.property-grid .table > tbody > tr > td:first-child {
+  width: 35px;
 }
-#fake-form .labels-block .fieldset-subgroup legend strong,
-#fake-form .labels-block.fieldset-subgroup legend strong {
-  position: relative;
-  top: 0;
+.property-grid .table > tbody > tr > td:nth-child(2),
+.property-grid .table > tbody > tr > td:nth-child(3) {
+  width: 75px;
 }
-#fake-form .labels-block .fieldset-subgroup ol,
-#fake-form .labels-block.fieldset-subgroup ol {
-  top: 0;
-  margin: 0;
-  padding: 0.5em 0 0;
+.property-grid .table > tbody > tr > td:nth-child(4) {
+  width: 65px;
 }
-/* element HIDDEN */
-#fake-form .formwizard-element.hidden-element {
-  cursor: default;
+.property-grid .table > tbody > tr > td:nth-child(5) {
+  width: 35px;
 }
-#fake-form .formwizard-element .hidden-dummy-element {
-  margin: 0;
-  padding: 5px;
-  border: 1px dotted #A9A9A9;
+.property-grid .table .btn {
+  background-color: #eee;
+  border-color: #bbb;
 }
-/* styles for drag and drop content */
-.x-dd-drag-ghost .formwizard-element {
-  list-style: none;
+.property-grid .sort-row-field {
+  cursor: move;
 }
-.x-dd-drop-icon {
-  top: 7px;
+.property-grid .ui-sortable-helper td {
+  border: none;
 }
-.x-dd-drag-ghost ol {
-  margin: 5px 0;
-  padding: 0;
-  list-style: none;
+.property-grid .ui-sortable-placeholder {
+  height: 45px;
+  border-left: 1px solid #c3c3c3 !important;
+  border-right: 1px solid #c3c3c3 !important;
+  outline-offset: -5px !important;
 }
-.x-dd-drag-ghost .buttongroup,
-.x-dd-drag-ghost label em,
-.x-dd-drag-ghost label strong {
-  display: none;
+#t3-form-stage-inner-container {
+  display: inline-block;
+  width: 90%;
+  text-align: left;
 }
-.x-dd-drag-ghost label {
-  margin: 0 10px 0 5px;
+@media (min-width: 1300px) {
+  #t3-form-stage-inner-container {
+    width: 600px;
+  }
 }
-.x-dd-drag-ghost legend {
-  margin: 0 5px;
-  font-size: 14px;
-  font-weight: bold;
-  color: #000;
+#t3-form-stage-container {
+  overflow: auto;
+  position: relative;
+  height: 100%;
+  text-align: left;
+}
+@media (min-width: 1300px) {
+  #t3-form-stage-container {
+    text-align: center;
+  }
+}
+#t3-form-stage-container ol,
+#t3-form-stage-container ul {
+  list-style: none;
+}
+#t3-form-stage-container .form-section {
   border: none;
 }
-.x-grid-panel .remove {
-  background-image: url("../Images/remove.gif");
-  width: 15px;
-  height: 16px;
+#t3-form-stage-container .panel-heading button {
+  outline: none;
 }
-.x-dd-drag-proxy,
-.x-dd-drop-nodrop {
-  background-color: #fff;
-  border-color: #c0c0c0;
+#t3-form-stage-container .panel-heading .paginiation-label {
+  margin-right: 1em;
 }
-.tab-content fieldset #formwizard {
-  display: inherit;
+#t3-form-stage-container .t3-form-new-element-container {
+  height: 62px;
+  border: 1px dashed #ddd;
+  text-align: center;
+  padding-top: 31px;
 }
-.tab-content fieldset.form-section {
-  float: left;
-  min-width: 380px;
-  width: 100%;
-  padding-bottom: 15px;
+#t3-form-stage-container .t3-form-new-element-container .btn {
+  transform: translateY(-50%);
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract ol,
+#t3-form-stage-container.t3-form-stage-viewmode-abstract ul {
+  padding-left: 40px;
+  padding-right: 1em;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-page-title {
+  margin: 0 0 0.5em;
 }
-.tab-content fieldset.form-section:last-child {
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage-inner-container {
+  overflow: hidden;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-composit:not(.t3-form-element-toplevel) {
   margin-bottom: 1em;
+  padding-bottom: 1px;
+  outline: 1px solid #dddddd;
+  outline-offset: -1px;
 }
-.tab-content fieldset.form-section ol#formwizard-right {
-  width: 100vw !important;
-  overflow: visible !important;
-  position: relative;
-  float: none;
-  left: 5px !important;
-  padding-top: 0;
-  padding-left: 0;
-  margin-right: 10px;
-  top: 30px !important;
-  display: table-cell;
-  height: auto !important;
-  list-style: none;
-  border-top-style: none;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-composit .sortable-hover {
+  outline-color: #777777;
 }
-.tab-content fieldset.form-section ol#formwizard-right.hover {
-  left: 0;
-  width: auto;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-composit .t3-form-form-composit-element-selected {
+  outline-color: #0078e6;
 }
-/* outer wrapper of whole wizard */
-#form-wizard-element {
-  z-index: 1;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-composit.sortable-hover > .ui-sortable-handle,
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-sortable-handle:hover {
+  border-color: #777777;
 }
-#form-wizard-element #formwizard-left {
-  display: table-cell;
-  float: left !important;
-  margin-right: -1px;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-composit.sortable-hover > .ui-sortable-handle .t3-form-icon-container,
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-sortable-handle:hover .t3-form-icon-container {
+  background-color: #777777;
 }
-#form-wizard-element #formwizard-left .x-tab-panel-body {
-  height: 100% !important;
-  overflow: visible !important;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-composit.sortable-hover > .ui-sortable-handle .t3-form-icon-container path,
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-sortable-handle:hover .t3-form-icon-container path {
+  fill: #fff;
 }
-/* inner wrapper of whole wizard */
-#formwizard {
-  background-color: #F8F8F8;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-sortable fieldset {
+  position: relative;
+  min-height: 130px;
+  padding-top: 5em;
 }
-/* applied when a element is moved */
-#formwizard.hover-move {
-  cursor: move;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-sortable fieldset legend {
+  position: absolute;
+  top: 1em;
+  display: inline-block;
+  width: 95%;
 }
-/* left panel */
-#formwizard-left.x-border-panel {
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-sortable-handle {
+  overflow: hidden;
   position: relative;
-  left: auto;
-  top: auto;
+  height: 62px;
+  margin-bottom: 1em;
+  border: 1px solid #ddd;
+  background-color: #fff;
 }
-/* tabs */
-#formwizard-left .x-tab-panel-header {
-  background-color: transparent;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-sortable-handle:hover .t3-form-validator-list {
+  right: 0;
+  transition: right 0.2s;
 }
-/* tabs inner */
-#formwizard-left .x-tab-strip {
-  margin-bottom: 0;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-sortable-handle:hover .t3-form-element-info .element-content span,
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-sortable-handle:hover .t3-form-element-info .element-content div {
+  color: #5a5a5a;
 }
-#formwizard-left .x-tab-strip-top .x-tab-left {
-  padding-right: 20px;
-}
-#formwizard-left .x-tab-strip-top .x-tab-right {
-  padding: 5px 10px 2px;
-  background-color: #EDEDED;
-  border-radius: 0;
-}
-#formwizard-left .x-tab-strip-top .x-tab-strip-active .x-tab-right,
-#formwizard-left .x-tab-strip-top .x-tab-strip-active.x-tab-strip-over .x-tab-right {
-  background-color: transparent;
-  border-bottom-color: #F8F8F8;
-}
-#formwizard-left .x-tab-strip-top .x-tab-strip-over .x-tab-right {
-  background-color: #E1E1E1;
-}
-#formwizard-left li.validation-error .x-tab-left,
-#formwizard-left div.validation-error .x-accordion-hd {
-  margin-right: 14px;
-  background-image: url("../../../../../t3skin/extjs/images/form/exclamation.gif");
-  background-position: right 1px;
-  background-repeat: no-repeat;
-}
-/* content below tabs */
-#formwizard-left .x-tab-panel-body-content {
-  min-height: 330px;
-  padding: 10px;
-  background: transparent;
-  border: 1px solid #C0C0C0;
-  border-top-width: 0;
-}
-/* info messages (also for drag and drop) */
-#formwizard-left .message-information,
-#fake-form .message-information,
-.x-dd-drag-ghost .message-information {
-  margin: 10px 0 15px 16px;
-  padding: 12px 10px;
-  background-image: none;
-  border-radius: 0;
-  box-shadow: none;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-sortable-handle:hover .t3-form-validator-info .t3-form-icon {
+  margin-right: 75px;
+  transition: margin 0.2s;
 }
-#formwizard-left .message-information p,
-#fake-form .message-information p,
-.x-dd-drag-ghost .message-information {
-  margin: 0;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-sortable-handle:has (.ui-sortable-handle:hover) {
+  border-color: transparent;
 }
-/* intro info messages */
-#formwizard-left #formwizard-left-elements-intro,
-#formwizard-left #formwizard-left-options-dummy,
-#fake-form .message-information {
-  margin: 0 0 10px;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-sortable-handle span {
+  color: #5a5a5a;
 }
-#formwizard-left .x-tab-panel-body,
-#formwizard-left .x-accordion-hd {
-  background: transparent none;
-  border-width: 0;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-state-disabled {
+  cursor: auto;
 }
-/* accordion */
-#formwizard-left .x-panel-accordion {
-  border-bottom: 1px solid #C7C7C7;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-state-disabled:hover {
+  background: none;
 }
-#formwizard-left .x-panel-accordion:last-child {
-  border-bottom: medium none;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .ui-sortable-placeholder {
+  margin-bottom: 1em;
 }
-/* headline of accordion */
-#formwizard-left .x-accordion-hd {
-  padding-left: 0;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-icon-container {
+  float: left;
+  width: 40px;
+  height: 100%;
+  padding: 1em;
+  cursor: move;
+  background-color: #ddd;
 }
-/* toggle icon of accordion */
-#formwizard-left .x-accordion-hd .x-tool-toggle {
-  margin: 0;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-icon-container .t3-form-icon {
+  height: 100%;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-form-element-body {
+  height: 100%;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-info {
+  position: relative;
   float: left;
-  background-image: url("../Images/module-menu-down.png");
-  background-position: 0 4px;
+  width: 55%;
+  height: 100%;
+  padding-left: 1em;
 }
-#formwizard-left .x-panel-collapsed .x-accordion-hd .x-tool-toggle {
-  background-image: url("../Images/module-menu-right.png");
-  background-position: 1px 3px;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-info:before,
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-info:after {
+  display: block;
+  content: '';
+  position: absolute;
+  bottom: 0;
+  right: 0;
+  left: 0;
 }
-#formwizard-left .x-accordion-hd .x-panel-header-text {
-  font-weight: bold;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-info:before {
+  height: 0.8em;
+  background: #fff;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-info:after {
+  bottom: 0.8em;
+  height: 1em;
+  background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, #fff 100%);
 }
-#formwizard-left .x-accordion-hd .x-panel-body {
-  padding-left: 15px;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-info .element-label-container {
+  float: left;
+  position: relative;
+  width: 45%;
+  height: 100%;
 }
-/* element inside accordion */
-#formwizard-left .x-form {
-  margin-left: 15px;
-  margin-top: 10px;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-info .element-label-container .element-label {
+  overflow: hidden;
+  position: absolute;
+  top: 50%;
+  width: 100%;
+  text-overflow: ellipsis;
+  transform: translateY(-50%);
 }
-#formwizard-left .x-form fieldset {
-  padding: 0;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-info .element-content {
+  padding-top: 1em;
+  white-space: nowrap;
+  font-size: 0.8em;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-info .element-content span,
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-element-info .element-content div {
+  color: #ddd;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-validator-info {
+  position: relative;
+  overflow: hidden;
+  float: right;
+  height: 100%;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-validator-info .t3-form-icon {
+  height: 100%;
+  z-index: 1;
+  margin-left: 1em;
+  transition: margin 0.3s;
+  filter: grayscale(100%);
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-validator-info .t3-form-validator-list {
+  position: absolute;
+  top: 0;
+  right: -100px;
+  width: 100px;
+  height: 100%;
+  padding: 1em 1em 1em 35px;
+  font-size: 0.8em;
+  transition: right 0.3s;
+  background-color: #ddd;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-validator-info .t3-form-validator-list:before,
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-validator-info .t3-form-validator-list:after {
+  display: block;
+  content: '';
+  position: absolute;
+  bottom: 0;
+  right: 0;
+  left: 0;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-validator-info .t3-form-validator-list:before {
+  height: 1em;
+  background: #ddd;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-validator-info .t3-form-validator-list:after {
+  bottom: 1em;
+  height: 1em;
+  background: linear-gradient(to bottom, rgba(221, 221, 221, 0) 0%, #ddd 100%);
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .t3-form-validator-info .validator-label {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  color: #5a5a5a;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected {
+  position: relative;
+  padding-top: 35px;
+  height: 97px;
   border: none;
 }
-#formwizard-left .x-form fieldset legend {
-  padding: 0;
-  font-size: 12px;
-  color: #222222;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .t3-form-form-element-body {
+  border: 1px solid #0078e6;
 }
-#formwizard-left .x-panel-tbar {
-  margin-top: 10px;
-  padding-left: 15px;
-  padding-bottom: 0;
-  border-width: 0;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .t3-form-icon-container {
+  background-color: #0078e6;
 }
-#formwizard-left .x-panel-tbar .x-toolbar {
-  padding: 0;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .t3-form-element-info .element-content span,
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .t3-form-element-info .element-content div {
+  color: #5a5a5a;
 }
-#formwizard-left .x-table-layout {
-  margin-bottom: 10px;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .t3-form-validator-list {
+  right: 0;
+  transition: right 0.2s;
+  background-color: #ebf3fb;
 }
-/* generic element like textfield */
-#formwizard-left .formwizard-element {
-  margin-left: 12px;
-  background-color: transparent;
-  background-image: none;
-  border-color: transparent;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .t3-form-validator-list:before {
+  background-color: #ebf3fb;
 }
-#formwizard-left .formwizard-element.x-btn-over {
-  background-color: #D5D5D5;
-  background-image: -moz-linear-gradient(center top, #F6F6F6 10%, #D5D5D5 90%);
-  border-color: #C0C0C0;
-  border-radius: 0;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .t3-form-validator-list:after {
+  background: linear-gradient(to bottom, rgba(235, 243, 251, 0) 0%, #ebf3fb 100%);
 }
-#formwizard-left .formwizard-element .x-btn-mc {
-  text-align: left;
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .t3-form-validator-info .t3-form-icon {
+  margin-right: 75px;
+  filter: none;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .btn-toolbar-container {
+  position: absolute;
+  top: 0;
+  right: 0;
+  width: 100%;
+  height: 35px;
+  border: 1px solid #0078e6;
+  background-color: #0078e6;
+  padding-right: 0.7em;
+  padding-top: 0.4em;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .btn-toolbar-container:before,
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .btn-toolbar-container:after {
+  position: absolute;
+  top: 0;
+  display: block;
+  width: 1px;
+  height: 100%;
+  content: ' ';
+  background-color: #0078e6;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .btn-toolbar-container:before {
+  left: -1px;
 }
-/* form elements in left panel */
-.formwizard-left-elements-basic-button {
-  background-image: url("../Images/ui-button.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .btn-toolbar-container:after {
+  right: -1px;
 }
-.formwizard-left-elements-basic-checkbox {
-  background-image: url("../Images/ui-check-box.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .btn-toolbar-container .dropdown-menu {
+  left: auto;
+  left: initial;
+  min-width: initial;
+  right: 0;
+  padding-left: 0;
+  padding-right: 0;
+  background-color: #005db3;
 }
-.formwizard-left-elements-basic-fieldset {
-  background-image: url("../Images/ui-group-box.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .btn-toolbar-container .dropdown-menu > li a:hover {
+  background-color: #006bcd;
 }
-.formwizard-left-elements-basic-fileupload {
-  background-image: url("../Images/drive-upload.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .btn-toolbar-container .caret {
+  color: #0078e6;
 }
-.formwizard-left-elements-basic-hidden {
-  background-image: url("../Images/ui-text-field-hidden.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .btn-toolbar-container .t3-form-dropdown-buttons .icon {
+  margin-right: 0.5em;
 }
-.formwizard-left-elements-basic-password {
-  background-image: url("../Images/ui-text-field-password.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .btn-toolbar-container .btn-toolbar {
+  float: right;
 }
-.formwizard-left-elements-basic-radio {
-  background-image: url("../Images/ui-radio-button.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .btn-toolbar-container .btn-toolbar .btn {
+  background-color: #fff;
+  border-color: #fff;
 }
-.formwizard-left-elements-basic-reset {
-  background-image: url("../Images/broom.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .btn-toolbar-container .btn-toolbar .btn:hover,
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .btn-toolbar-container .btn-toolbar .btn.active {
+  background-color: #ebf3fb;
 }
-.formwizard-left-elements-basic-select {
-  background-image: url("../Images/ui-combo-box.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .btn-toolbar-container .btn-toolbar .icon svg path {
+  fill: #0078e6;
 }
-.formwizard-left-elements-basic-submit {
-  background-image: url("../Images/ui-button-default.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .meta-label {
+  display: inline-block;
+  top: 1em;
+  left: 5em;
+  bottom: auto;
+  font-size: 0.9em;
+  color: #fff;
 }
-.formwizard-left-elements-basic-textarea {
-  background-image: url("../Images/ui-scroll-pane-text.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract #t3-form-stage .t3-form-form-element-selected .meta-label span {
+  color: #fff;
 }
-.formwizard-left-elements-basic-textline {
-  background-image: url("../Images/ui-text-field.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .panel.t3-form-form-stage-selected {
+  border-color: #0078e6;
 }
-.formwizard-left-elements-predefined-checkboxgroup {
-  background-image: url("../Images/ui-check-boxes.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .panel.t3-form-form-stage-selected > .panel-heading {
+  background-color: #0078e6;
+  border-color: #0078e6;
+  color: #fff;
 }
-.formwizard-left-elements-predefined-email {
-  background-image: url("../Images/mail.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .panel.t3-form-form-stage-selected > .panel-heading .btn {
+  background-color: #fff;
+  border-color: #fff;
 }
-.formwizard-left-elements-predefined-name {
-  background-image: url("../Images/user-silhouette.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .panel.t3-form-form-stage-selected > .panel-heading .btn:hover,
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .panel.t3-form-form-stage-selected > .panel-heading .btn.active {
+  background-color: #ebf3fb;
 }
-.formwizard-left-elements-predefined-radiogroup {
-  background-image: url("../Images/ui-radio-buttons.png");
+#t3-form-stage-container.t3-form-stage-viewmode-abstract .panel.t3-form-form-stage-selected > .panel-heading .icon svg path {
+  fill: #0078e6;
 }
-.formwizard-left-elements-content-header {
-  background-image: url("../Images/edit-heading.png");
+#t3-form-stage-container.t3-form-stage-viewmode-preview input[type="text"],
+#t3-form-stage-container.t3-form-stage-viewmode-preview input[type="date"],
+#t3-form-stage-container.t3-form-stage-viewmode-preview input[type="password"],
+#t3-form-stage-container.t3-form-stage-viewmode-preview textarea,
+#t3-form-stage-container.t3-form-stage-viewmode-preview select {
+  color: #000;
+  background-color: #e5e5e5;
 }
-.formwizard-left-elements-content-textblock {
-  background-image: url("../Images/edit-textblock.png");
+#t3-form-stage-container.t3-form-stage-viewmode-preview ::-webkit-input-placeholder {
+  color: #737373;
+  font-style: italic;
 }
-#formwizard-left .x-form-text {
-  height: 17px;
+#t3-form-stage-container.t3-form-stage-viewmode-preview ::-moz-placeholder {
+  color: #737373;
+  font-style: italic;
 }
-#formwizard-left .x-btn-text-icon .x-btn-icon-small-left .x-btn-text {
-  color: black;
+#t3-form-stage-container.t3-form-stage-viewmode-preview :-ms-input-placeholder {
+  color: #737373;
+  font-style: italic;
 }
-#formwizard-left .x-small-editor .x-form-text {
-  height: 13px !important;
+#t3-form-stage-container.t3-form-stage-viewmode-preview ::placeholder {
+  color: #737373;
+  font-style: italic;
 }
-/* icon in element field for applying entered text */
-#formwizard-left .x-form-field-wrap .x-form-submit-trigger {
-  background-image: url("../Images/submit-trigger.gif");
+#t3-form-stage-container.t3-form-stage-viewmode-preview input[type="date"] {
+  display: block;
+  width: 100%;
+  height: 32px;
+  padding: 0.6em;
+  font-size: 12px;
+  line-height: 1.5;
+  background-image: none;
+  border: 1px solid #c3c3c3;
+  border-radius: 2px;
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+  transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
 }
-/* right panel */
-#formwizard-right {
-  min-height: 350px;
-  padding: 30px 0 10px 2px;
-  overflow: visible;
+#t3-form-stage-container.t3-form-stage-viewmode-preview select[multiple="multiple"] {
+  height: auto;
+  min-height: 32px;
 }
-#fake-form {
-  padding: 10px;
-  background-color: tansparent;
-  border: 1px solid #C0C0C0;
+#t3-form-stage-container.t3-form-stage-viewmode-preview textarea {
+  min-height: 100px;
 }
-#fake-form li {
-  overflow: visible;
+#t3-form-stage-container.t3-form-stage-viewmode-preview legend.t3-form-form-element-selected {
+  border-color: #c3c3c3;
 }
-/* visible area of element on right panel */
-#fake-form div.overflow-hidden {
-  overflow: hidden;
+#t3-form-stage-container.t3-form-stage-viewmode-preview .form-navigation .btn-group span,
+#t3-form-stage-container.t3-form-stage-viewmode-preview .form-navigation .btn-group button {
+  display: inline-block;
+  margin-right: 1em;
 }
-#fake-form div.overflow-hidden input {
-  margin-left: 1px;
+#t3-form-stage-container.t3-form-stage-viewmode-preview .preview-table-first-col {
+  width: 30%;
 }
-/* wrap around all elements on right panel */
-#fake-form .formwizard-element {
-  border: 1px solid transparent;
+#t3-form-stage-container.t3-form-stage-viewmode-preview .t3-form-element-preview {
   position: relative;
+  display: inline-block;
+  width: 100%;
+}
+#t3-form-stage-container.t3-form-stage-viewmode-preview .t3-form-new-element-container {
+  display: none;
 }
-#fake-form .formwizard-element.hover,
-#fake-form .formwizard-element.hidden.hover {
-  background-color: #F9FCFF;
-  border: 1px solid #C5DBE6;
+#t3-form-stage-container.t3-form-stage-viewmode-preview .t3-form-element-toplevel > form > .tooltip {
+  top: 100px !important;
 }
-#fake-form .formwizard-element.active,
-#fake-form .formwizard-element.hidden.active {
-  background-color: #EAF7FF;
-  border: 1px solid #C5DBE6;
+#t3-form-stage-container #t3-form-stage {
+  margin-bottom: 0;
+  padding-top: 0.5em;
+}
+#t3-form-stage-container #t3-form-stage > ol,
+#t3-form-stage-container #t3-form-stage > ol > li > ol {
+  padding-left: 0;
+  padding-right: 0;
 }
-#fake-form .formwizard-element.hidden {
-  min-height: 1em;
-  background-color: transparent;
-  border: 1px dotted #C5DBE6;
+#t3-form-stage-container #t3-form-stage .t3-form-element-toplevel > .t3-form-form-element-selected {
+  height: auto;
+  padding-top: 0;
 }
-/* toolbar on each element */
-#fake-form .formwizard-element div.buttongroup {
+#t3-form-stage-container #t3-form-stage .t3-form-element-toplevel > .t3-form-form-element-selected .btn-toolbar-container {
+  display: none;
+}
+.meta-label {
+  z-index: 1;
   position: absolute;
-  right: 0;
-  top: -35px;
+  bottom: 1em;
+  left: 5.5em;
   display: none;
+  color: #0078e6;
+  line-height: 1.6;
+  font-size: 0.8em;
+}
+.ui-sortable-handle:hover > .meta-label {
+  display: inline-block;
+}
+.ui-sortable-placeholder,
+.t3-form-element-composit.ui-sortable-placeholder {
+  background-color: #fff !important;
+  border: none !important;
+  outline: 1px dashed #c4dbab !important;
+  outline-offset: -2px !important;
+  visibility: visible !important;
+}
+.t3-form-icon {
+  margin-right: 1em;
+}
+.t3-form-validation-child-has-error {
+  color: #c83c3c;
+}
+#t3-form-navigation-component .t3-form-validation-errors,
+#t3-form-stage-container .t3-form-validation-errors {
+  position: relative;
+  color: #c83c3c;
+}
+#t3-form-navigation-component .t3-form-validation-errors:before,
+#t3-form-stage-container .t3-form-validation-errors:before {
   z-index: 1;
-  padding: 4px 3px 12px;
-  background-image: url("../Images/tooltip.png");
+  position: absolute;
+  display: inline-block;
+  width: 15px;
+  height: 15px;
+  font-family: FontAwesome;
+  vertical-align: middle;
+  border-radius: 50%;
+  font-size: 1em;
+  line-height: 1.4;
+  text-align: center;
+  background: none;
+}
+#t3-form-navigation-component .t3-form-validation-errors:hover:before,
+#t3-form-navigation-component .t3-form-validation-errors.t3-form-form-element-selected:before {
+  left: 2.4em;
+}
+#t3-form-navigation-component .t3-form-validation-errors:before {
+  margin-top: 0.2em;
+  color: #fff;
+  font-size: 10px;
+  font-weight: 800;
+  content: "\f12a";
+  background-color: #c83c3c;
 }
-#fake-form .formwizard-element.hover > div.buttongroup,
-#fake-form .formwizard-element.active > div.buttongroup {
-  display: block;
+.t3-form-validation-errors#t3-form-navigation-component-tree-root:before {
+  left: -2em !important;
+  margin-top: 0.1em;
 }
-#fake-form .formwizard-element div.buttongroup button {
-  width: 16px;
-  height: 16px;
-  background-color: transparent;
-  border: 0 solid transparent;
+#t3-form-stage-container .t3-form-validation-errors.ui-sortable-handle {
+  border-color: #c83c3c;
 }
-#fake-form .formwizard-element div.buttongroup span {
-  margin: 0 3px;
+#t3-form-stage-container .t3-form-validation-errors.ui-sortable-handle:before {
+  left: 4.5em;
+  margin-top: 1.9em;
+  content: "\f071";
 }
-#fake-form .formwizard-element div.buttongroup span.x-btn-over {
-  background-color: transparent;
-  background-image: none;
+#t3-form-stage-container .t3-form-validation-errors.ui-sortable-handle .element-label {
+  padding-left: 1.5em;
 }
-#fake-form .formwizard-element button.t3-icon-edit-delete {
-  background-image: url('../../../../core/Resources/Public/Icons/T3Icons/actions/actions-delete.svg');
+#t3-form-inspector-panels .t3-form-collection-element .t3-form-validation-errors {
+  display: inline-block;
+  color: #fff;
+  font-size: 0.8em;
+  font-weight: 700;
+  background-color: #c83c3c;
+  margin-top: 0.5em;
+  padding: 0.1em 0.5em;
+  border-radius: 2px;
+}
+#t3-form-inspector-panels .t3-form-validation-errors.t3-form-collection-element {
+  border-color: #c83c3c;
+}
+#t3-form-inspector-panels .t3-form-validation-errors.t3-form-collection-element h4 {
+  border-color: #c83c3c;
+  background-color: #c83c3c;
+  color: #fff;
+}
+#t3-form-inspector-panels .t3-form-validation-errors.t3-form-collection-element h4 path {
+  fill: #fff;
+}
+#t3-form-inspector-panels .t3-form-validation-errors.t3-form-collection-element .t3-form-collection-element-remove-button {
+  background: #fff;
+  border-color: transparent;
 }
-#fake-form .formwizard-element button.t3-icon-document-open {
-  background-image: url('../../../../core/Resources/Public/Icons/T3Icons/actions/actions-open.svg');
+#t3-form-inspector-panels .t3-form-validation-errors.t3-form-collection-element .t3-form-collection-element-remove-button path {
+  fill: #c83c3c;
 }
-@media only screen and (max-width: 615px) {
-  .tab-content fieldset.form-section ol#formwizard-right {
-    left: 0 !important;
-  }
+.form-editor-loading-spinner {
+  width: 150px;
+  margin: 5em auto 0;
+  text-align: center;
+}
+.ui-sortable-handle {
+  cursor: pointer;
+}
+.module[data-module-name="web_FormFormbuilder_FormEditor"] {
+  overflow: hidden;
+}
+.module[data-module-name="web_FormFormbuilder_FormEditor"] .module-body,
+.module[data-module-name="web_FormFormbuilder_FormEditor"] div[data-identifier="moduleWrapper"] {
+  height: 100%;
+}
+.module[data-module-name="web_FormFormbuilder_FormEditor"] .module-body {
+  padding-bottom: 0.5em;
+}
+.module[data-module-name="web_FormFormbuilder_FormEditor"] .module-docheader-bar-column-left button,
+.module[data-module-name="web_FormFormbuilder_FormEditor"] .module-docheader-bar-column-left button:focus,
+.module[data-module-name="web_FormFormbuilder_FormEditor"] .module-docheader-bar-column-left button:active {
+  outline: 0;
+  outline-color: initial;
+  outline-style: initial;
+  outline-width: 0px;
+}
+.module[data-module-name="web_FormFormbuilder_FormEditor"] .module-docheader-bar-column-left .btn-group {
+  margin-left: 25px;
+}
+.t3-form-element-new-page-button {
+  position: absolute;
+  left: 0.5em;
 }
diff --git a/typo3/sysext/form/Resources/Public/Images/advanced-password.svg b/typo3/sysext/form/Resources/Public/Images/advanced-password.svg
new file mode 100644
index 0000000000000000000000000000000000000000..14626a4e4b8ad0452fcbfee6191f5f6f45a08d97
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/advanced-password.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#676767;" d="M2,5.3h1.6V3.7H2V5.3z M4.5,5.3h1.6V3.7H4.5V5.3z M7,3.7v1.6h1.6V3.7H7z M2,12.3h1.6v-1.6H2V12.3z
+	 M4.5,12.3h1.6v-1.6H4.5V12.3z M7,12.3h1.6v-1.6H7V12.3z"/>
+<path style="fill:#9A9999;" d="M0,2v5h16V2H0z M15,6H1V3h14V6z M0,14h16V9H0V14z M1,10h14v3H1V10z"/>
+<path style="fill:#FFFFFF;" d="M1,3v3h14V3H1z M3.6,5.3H2V3.7h1.6V5.3z M6.1,5.3H4.5V3.7h1.6V5.3z M8.6,5.3H7V3.7h1.6V5.3z M1,13h14
+	v-3H1V13z M7,10.7h1.6v1.6H7V10.7z M4.5,10.7h1.6v1.6H4.5V10.7z M2,10.7h1.6v1.6H2V10.7z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/broom.png b/typo3/sysext/form/Resources/Public/Images/broom.png
deleted file mode 100644
index 5aa25bd5380ddc618de9f4e839efb82a81a78f34..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/broom.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/captcha.jpg b/typo3/sysext/form/Resources/Public/Images/captcha.jpg
deleted file mode 100644
index 6bf02825b6c29a47659ba88845d1c42b670f572d..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/captcha.jpg and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/checkbox.svg b/typo3/sysext/form/Resources/Public/Images/checkbox.svg
new file mode 100644
index 0000000000000000000000000000000000000000..2dcb3d81cf8f95a5eac4c6cb16f0db3fdd1421e2
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/checkbox.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#FFFFFF;" d="M15,15V1H1v14H15z M4.1,8l2.1,2.1l5.7-5.6l0.7,0.7l-5.7,5.6l-0.7,0.7l-0.7-0.7L3.4,8.7L4.1,8z"/>
+<path style="fill:#9A9999;" d="M15,0H1H0v1v14v1h1h14h1v-1V1V0H15z M15,15H1V1h14V15z"/>
+<polygon style="fill:#676767;" points="11.9,4.5 6.2,10.1 4.1,8 3.4,8.7 6.2,11.5 6.9,10.8 12.6,5.2 "/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/content-element.svg b/typo3/sysext/form/Resources/Public/Images/content-element.svg
new file mode 100644
index 0000000000000000000000000000000000000000..8b61701617cded0874bca33388419ce9f352db19
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/content-element.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#FFFFFF;" d="M15,15V1H1v14H15z M9,2h5v2H9V2z M9,5h5v1H9V5z M9,7h5v1H9V7z M2,2h6v6H2V2z M2,9h12v1H2V9z M2,11h12
+	v1H2V11z M2,13h12v1H2V13z"/>
+<path style="fill:#9A9999;" d="M15,0H1H0v1v14v1h1h14h1v-1V1V0H15z M15,15H1V1h14V15z"/>
+<path style="fill:#676767;" d="M8,2H2v6h6V2z M9,6h5V5H9V6z M9,8h5V7H9V8z M2,10h12V9H2V10z M2,12h12v-1H2V12z M2,14h12v-1H2V14z
+	 M9,2v2h5V2H9z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/cursor-move.png b/typo3/sysext/form/Resources/Public/Images/cursor-move.png
deleted file mode 100644
index de8bca52035bd0d4918c5ff98e68b963c936fe2e..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/cursor-move.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/date-picker.svg b/typo3/sysext/form/Resources/Public/Images/date-picker.svg
new file mode 100644
index 0000000000000000000000000000000000000000..c785eb2bc94f2484af59e20d1a5f6baf5d40f688
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/date-picker.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#FFFFFF;" d="M4.8,8h2.9V5H4.8H4.7v3H4.8z M1,5h3v3H1V5z M4.7,8.5v3h0.1h2.9v-3H4.8H4.7z M1,8.5h3v3H1V8.5z
+	 M4.8,12H4.7v3h0.1h2.9v-3H4.8z M1,12h3v3H1V12z M12,5h3v3h-3V5z M11.2,8h0.1V5h-0.1H8.3v3H11.2z M8.3,8.5v3h2.9h0.1v-3h-0.1H8.3z
+	 M12,8.5h3v3h-3V8.5z M12,12h3v3h-3V12z M11.2,12H8.3v3h2.9h0.1v-3H11.2z M4.8,2V1H3v1v2h1.8V2z M13,2V1h-1.8v1v2H13V2z"/>
+<path style="fill:#8C8C8C;" d="M12,5h-0.7v3h-0.1H8.3V5H7.7v3H4.8H4.7V5H4v3H1v0.5h3v3H1V12h3v3h0.7v-3h0.1h2.9v3h0.6v-3h2.9h0.1v3
+	H12v-3h3v-0.5h-3v-3h3V8h-3V5z M7.7,11.5H4.8H4.7v-3h0.1h2.9V11.5z M11.3,11.5L11.3,11.5h-3v-3h2.9h0.1
+	C11.3,8.5,11.3,11.5,11.3,11.5z"/>
+<path style="fill:#676767;" d="M15,2h-1V1V0h-1h-1.8h-1v1v1H5.7V1V0h-1H3H2v1v1H1H0v2v1v6.5V12v3v1h1h3.2h0.5h3h0.5h3h0.5H15h1v-1
+	v-3v-0.5v-3V8V5V4V2H15z M11.2,2V1H13v1v2h-1.8V2z M3,2V1h1.8v1v2H3V2z M15,8v0.5v3V12v3h-3h-0.7h-0.1H8.3H7.7H4.8H4.7H4H1v-3v-0.5
+	v-3V8V5h3h0.7h0.1h2.9h0.6h2.9h0.1H12h3V8z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/drive-upload.png b/typo3/sysext/form/Resources/Public/Images/drive-upload.png
deleted file mode 100644
index f25934d2aa9e9836dff357459ffcb63eef2e07fd..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/drive-upload.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/duplicate.svg b/typo3/sysext/form/Resources/Public/Images/duplicate.svg
new file mode 100644
index 0000000000000000000000000000000000000000..c785b6d552c0ebfa42254ac6468f7feea778b0f4
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/duplicate.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path d="M14,4h-2V2V1h-1H2H1v1v9v1h1h2v2v1h1h9h1v-1V5V4H14z M4,4v1v6H2V2h9v2H5H4z M14,14H5V5h9V14z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/edit-heading.png b/typo3/sysext/form/Resources/Public/Images/edit-heading.png
deleted file mode 100644
index 0817b4930a2e7d7b0fc97107cc2d0f4a984baf11..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/edit-heading.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/edit-textblock.png b/typo3/sysext/form/Resources/Public/Images/edit-textblock.png
deleted file mode 100644
index a27655f38a72eb74a1aa6470700a8a6c0667e407..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/edit-textblock.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/fieldset.svg b/typo3/sysext/form/Resources/Public/Images/fieldset.svg
new file mode 100644
index 0000000000000000000000000000000000000000..915bea8c10c25318fde4535b45bc3ea8c9243717
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/fieldset.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#9A9999;" d="M10,0v1h5v14H1V1h1V0H0v16h16V0H10z M2,14h12v-3.5H2V14z M3,11.5h10V13H3V11.5z M14,6.2H2v3.6h12V6.2
+	z M13,8.8H3V7.2h10V8.8z M14,2H2v3.5h12V2z M13,4.5H3V3h10V4.5z"/>
+<rect x="3" style="fill:#676767;" width="6" height="1"/>
+<path style="fill:#FFFFFF;" d="M13,7.2H3v1.6h10V7.2z M13,11.5H3V13h10V11.5z M10,1V0H9v1H3V0H2v1H1v14h14V1H10z M14,14H2v-3.5h12
+	V14z M14,9.8H2V6.2h12V9.8z M14,5.5H2V2h12V5.5z M13,3H3v1.5h10V3z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/file-upload.svg b/typo3/sysext/form/Resources/Public/Images/file-upload.svg
new file mode 100644
index 0000000000000000000000000000000000000000..ae73a246e294ceb79580f77ba8c192dcf7543c63
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/file-upload.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#9A9999;" d="M2,0v16h12V4l-4-4H2z M3,1h6v4h4v10H3V1z M10,1.4L12.6,4H10V1.4z"/>
+<path style="fill:#676767;" d="M8,4L5,8h2v4h2V8h2L8,4z"/>
+<path style="fill:#FFFFFF;" d="M10,4V1.4L12.6,4H10z M9,1H3v14h10v-5L9,5V1z M11,8H9v4H7V8H5l3-4L11,8z"/>
+<path style="fill:#CBCBCB;" d="M13,5v5L9,5H13z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/finisher.svg b/typo3/sysext/form/Resources/Public/Images/finisher.svg
new file mode 100644
index 0000000000000000000000000000000000000000..3d8c355369b31fd0dc2220c6e7bd6ddfc2fd064a
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/finisher.svg
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#676767;" d="M12.9,3.8l-1.4-0.4c0-0.1-0.1-0.2-0.1-0.3l0.7-1.2c0-0.1,0-0.1,0-0.2L11.4,1c-0.1-0.1-0.1-0.1-0.2,0
+	L9.9,1.6c-0.1,0-0.2-0.1-0.3-0.1L9.2,0.1C9.2,0,9.1,0,9,0H8C7.9,0,7.8,0,7.8,0.1L7.4,1.5c-0.1,0-0.2,0.1-0.3,0.1L5.9,0.9
+	c-0.1,0-0.1,0-0.2,0L4.9,1.7c-0.1,0.1-0.1,0.1,0,0.2l0.7,1.2c0,0.1-0.1,0.2-0.1,0.3L4.1,3.8C4,3.8,4,3.9,4,4v1c0,0.1,0,0.1,0.1,0.2
+	l1.4,0.4c0,0.1,0.1,0.2,0.1,0.3L4.9,7.1c0,0.1,0,0.1,0,0.2L5.6,8c0.1,0.1,0.1,0.1,0.2,0L7,7.3c0.1,0,0.2,0.1,0.3,0.1l0.4,1.4
+	C7.8,9,7.9,9,8,9h1c0.1,0,0.1,0,0.2-0.1l0.4-1.4c0.1,0,0.2-0.1,0.3-0.1l1.2,0.7c0.1,0,0.1,0,0.2,0L12,7.4c0.1-0.1,0.1-0.1,0-0.2
+	L11.3,6c0-0.1,0.1-0.2,0.1-0.3l1.4-0.4C13,5.2,13,5.1,13,5V4C13,3.9,13,3.8,12.9,3.8L12.9,3.8z M8.5,6.4c-1.1,0-1.9-0.9-1.9-1.9
+	s0.9-1.9,1.9-1.9c1.1,0,1.9,0.9,1.9,1.9S9.6,6.4,8.5,6.4z M5.9,10.6L5.1,10c0-0.1,0-0.2,0-0.2l0.7-0.6V9.1L5.6,8.5L5.5,8.4L4.6,8.5
+	c-0.1,0-0.1-0.1-0.2-0.1l0.1-0.9c0,0,0-0.1-0.1-0.1L3.8,7.1H3.7L3.1,7.9c-0.1,0-0.2,0-0.2,0L2.2,7.1H2.1L1.5,7.4L1.4,7.5l0.1,0.9
+	c0,0.1-0.1,0.1-0.1,0.2l-1-0.1c0,0-0.1,0-0.1,0.1L0.1,9.2v0.1l0.8,0.6c0,0.1,0,0.2,0,0.2l-0.7,0.6v0.1l0.3,0.6l0.1,0.1l0.9-0.1
+	c0.1,0.1,0.1,0.1,0.2,0.2l-0.1,0.9c0,0,0,0.1,0.1,0.1l0.6,0.3h0.1L3,12.1c0.1,0,0.2,0,0.2,0l0.6,0.7h0.1l0.6-0.3l0.1-0.1l-0.1-0.9
+	c0.1-0.1,0.1-0.1,0.2-0.2l0.9,0.1c0,0,0.1,0,0.1-0.1L5.9,10.6C5.9,10.7,5.9,10.7,5.9,10.6L5.9,10.6z M2.5,11.2c-0.7-0.3-1-1-0.7-1.7
+	s1-1,1.7-0.7s1,1,0.7,1.7S3.2,11.5,2.5,11.2z"/>
+<path style="fill:#79A548;" d="M15.9,12.6l-4.4-3.3v2.2H7.1v2.2h4.4v2.1L15.9,12.6z"/>
+<path style="fill:#FFFFFF;" d="M8.5,2.6c-1,0-1.9,0.9-1.9,1.9s0.8,1.9,1.9,1.9s1.9-0.9,1.9-1.9S9.6,2.6,8.5,2.6z M3.5,8.8
+	c-0.7-0.3-1.4,0-1.7,0.7s0,1.4,0.7,1.7s1.4,0,1.7-0.7S4.2,9.1,3.5,8.8z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/image-upload.svg b/typo3/sysext/form/Resources/Public/Images/image-upload.svg
new file mode 100644
index 0000000000000000000000000000000000000000..0b35d9c06bf8cd92d2af58c53f96e7276a7fddbb
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/image-upload.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#FFFFFF;" d="M15,13V1H1v12H15z M8,4l3,4H9v4H7V8H5L8,4z"/>
+<path style="fill:#9A9999;" d="M1,0H0v1v14v1h1h14h1V0H1z M15,13H1V1h14V13z"/>
+<path style="fill:#676767;" d="M8,4L5,8h2v4h2V8h2L8,4z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/insert-after.svg b/typo3/sysext/form/Resources/Public/Images/insert-after.svg
new file mode 100644
index 0000000000000000000000000000000000000000..7289fa5687885834ce2668b8c84479d2a89cb60d
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/insert-after.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#FFFFFF;" d="M3,3h10v2H3V3z"/>
+<path style="fill:#FFFFFF;" d="M15,0h-5v1h5v6H1V1h1V0H1H0v1v6v1h1h14h1V7V1V0H15z M13,2H3H2v1v2v1h1h10h1V5V3V2H13z M13,5H3V3h10V5
+	z"/>
+<path style="fill:#FFFFFF;" d="M3,0h6v1H3V0z M10.5,11.5h-2v-2h-1v2h-2v1h2v2h1v-2h2V11.5z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/insert-in.svg b/typo3/sysext/form/Resources/Public/Images/insert-in.svg
new file mode 100644
index 0000000000000000000000000000000000000000..95e00bee41f4fcb71ca1bf19dfbb21e0a9610b50
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/insert-in.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#FFFFFF;" d="M3,3h10v2H3V3z"/>
+<path style="fill:#FFFFFF;" d="M15,0h-5v1h5v14H1V1h1V0H1H0v1v14v1h1h14h1v-1V1V0H15z M13,2H3H2v1v2v1h1h10h1V5V3V2H13z M13,5H3V3
+	h10V5z"/>
+<path style="fill:#FFFFFF;" d="M3,0h6v1H3V0z M10.5,9.8h-2v-2h-1v2h-2v1h2v2h1v-2h2V9.8z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/mail.png b/typo3/sysext/form/Resources/Public/Images/mail.png
deleted file mode 100644
index a5fdc0c2b2f204c3659adb15c00de5c2f70631bf..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/mail.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/module-menu-down.png b/typo3/sysext/form/Resources/Public/Images/module-menu-down.png
deleted file mode 100644
index 6829ed2920b732c50567cffe0b5b267ec15af5cd..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/module-menu-down.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/module-menu-right.png b/typo3/sysext/form/Resources/Public/Images/module-menu-right.png
deleted file mode 100644
index 7b87ed4cb8c03959295736f6704716eee8dd97a2..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/module-menu-right.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/multi-checkbox.svg b/typo3/sysext/form/Resources/Public/Images/multi-checkbox.svg
new file mode 100644
index 0000000000000000000000000000000000000000..b8ff71da1b125b3f785a9b703cc74ffece1b3db4
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/multi-checkbox.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#9A9999;" d="M4.3,16h7.5V8.5H4.3V16z M5.3,9.6h5.4v5.4H5.3V9.6z M4.3,0v7.5h7.5V0H4.3z M10.7,6.4H5.3V1.1h5.4V6.4
+	z"/>
+<path style="fill:#676767;" d="M7.3,12.9L6.4,12l-0.5,0.5l1.4,1.4l0.5-0.5l2.3-2.3l-0.5-0.5L7.3,12.9z M7.8,4.9l2.3-2.3L9.6,2.1
+	L7.3,4.4L6.4,3.5L5.9,4l1.4,1.4L7.8,4.9z"/>
+<path style="fill:#FFFFFF;" d="M5.3,14.9h5.4V9.6H5.3V14.9z M6.4,12l0.9,0.9l2.3-2.3l0.5,0.5l-2.3,2.3l-0.5,0.5l-1.4-1.4L6.4,12z
+	 M5.3,1.1v5.4h5.4V1.1H5.3z M7.8,4.9L7.3,5.4L5.9,4l0.5-0.5l0.9,0.9l2.3-2.3l0.5,0.5L7.8,4.9z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/multi-select.svg b/typo3/sysext/form/Resources/Public/Images/multi-select.svg
new file mode 100644
index 0000000000000000000000000000000000000000..2621d8de455f2c8ad8fc3dfc698b54c63dd173b0
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/multi-select.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#9A9999;" d="M4.3,16h7.5V8.5H4.3V16z M5.3,9.6h5.4v5.4H5.3V9.6z M4.3,0v7.5h7.5V0H4.3z M10.7,6.4H5.3V1.1h5.4V6.4
+	z"/>
+<path style="fill:#676767;" d="M8,13.4l-0.9-0.9L6.6,13L8,14.4L9.4,13l-0.5-0.5L8,13.4z M6.6,11.5L7.1,12L8,11.1L8.9,12l0.5-0.5
+	L8,10.1L6.6,11.5z M8,4.9L7.1,4L6.6,4.5L8,5.9l1.4-1.4L8.9,4L8,4.9z M8,2.6l0.9,0.9L9.4,3L8,1.6L6.6,3l0.5,0.5L8,2.6z"/>
+<g>
+	<path style="fill:#FFFFFF;" d="M5.3,1.1v5.4h5.4V1.1H5.3z M8,5.9L6.6,4.5L7.1,4L8,4.9L8.9,4l0.5,0.5L8,5.9z M8.9,3.5L8,2.6L7.1,3.5
+		L6.6,3L8,1.6L9.4,3L8.9,3.5z"/>
+	<path style="fill:#FFFFFF;" d="M5.3,14.9h5.4V9.6H5.3V14.9z M8,10.1l1.4,1.4L8.9,12L8,11.1L7.1,12l-0.5-0.5L8,10.1z M7.1,12.5
+		L8,13.4l0.9-0.9L9.4,13L8,14.4L6.6,13L7.1,12.5z"/>
+</g>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/page.svg b/typo3/sysext/form/Resources/Public/Images/page.svg
new file mode 100644
index 0000000000000000000000000000000000000000..26fbff4224810c34441e8634e6a4fb725a95021d
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/page.svg
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#999999;" d="M3,15V1h6v4h4v1.6h1V4l-4-4H2v16h3v-1H3z M10,1.4L12.6,4H10V1.4z"/>
+<path style="fill:#CBCBCB;" d="M9.5,5.7l1-0.7H9L9.5,5.7z M10.5,5l2.2,1.6H13V5H10.5z"/>
+<path style="fill:#FFE6BB;" d="M5.8,9.5l0.8,0.6V8.7L5.8,9.3V9.5z M9.6,6.6h1.7L10.5,6L9.6,6.6z M14.4,8.9v1.3l0.8-0.6V9.5L14.4,8.9
+	z"/>
+<path style="fill:#FFFFFF;" d="M9.5,5.7L9,5V1H3v14h2V8.9l1.6-1.1V6.6h1.6L9.5,5.7z M10,1.4V4h2.6L10,1.4z M7.4,7.4v3.3l3.1,2.3
+	l3.1-2.2V7.4H7.4z"/>
+<polygon style="fill:#666666;" points="6.6,6.6 6.6,10.1 7.4,10.7 7.4,7.4 13.6,7.4 13.6,10.8 14.4,10.2 14.4,6.6 "/>
+<path style="fill:#B9B9B9;" d="M9.3,12.1h2.5l1.1-0.8H8.2L9.3,12.1z M8.2,10.5h4.7V9.7H8.2V10.5z M8.2,8.2V9h4.7V8.2H8.2z"/>
+<path style="fill:#FFC857;" d="M5.8,10.4v4.8l2.7-2.8L5.8,10.4z M12.5,12.5l2.7,2.8v-4.8L12.5,12.5z M10.5,13.8l-1.3-0.9l-2.3,2.3
+	h7.2l-2.3-2.3L10.5,13.8z"/>
+<path style="fill:#E8A33D;" d="M10.5,6l0.8,0.6h1.4L10.5,5L8.2,6.6h1.4L10.5,6z M14.4,7.8v1.1l0.8,0.6v0.1L10.5,13L5.8,9.5V9.3
+	l0.8-0.6v-1L5,8.9V16h11V8.9L14.4,7.8z M5.8,10.4l2.7,2l-2.7,2.8V10.4z M6.9,15.2l2.3-2.3l1.3,0.9l1.3-0.9l2.3,2.3H6.9z M15.2,15.3
+	l-2.7-2.8l2.7-2V15.3z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/password.svg b/typo3/sysext/form/Resources/Public/Images/password.svg
new file mode 100644
index 0000000000000000000000000000000000000000..2dc97b8d452a3fa323d4eed7d5905ac940091995
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/password.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<rect x="2" y="7.2" style="fill:#676767;" width="1.6" height="1.6"/>
+<rect x="4.5" y="7.2" style="fill:#676767;" width="1.6" height="1.6"/>
+<rect x="7" y="7.2" style="fill:#676767;" width="1.6" height="1.6"/>
+<path style="fill:#9A9999;" d="M0,5.5L0,5.5v2v3h1h14h1v-3v-2l0,0h-1 M15,9.5H1v-3h14V9.5z"/>
+<path style="fill:#FFFFFF;" d="M1,6.5v3h14v-3H1z M3.6,8.8H2V7.2h1.6V8.8z M6.1,8.8H4.5V7.2h1.6V8.8z M8.6,8.8H7V7.2h1.6V8.8z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/radio-button.svg b/typo3/sysext/form/Resources/Public/Images/radio-button.svg
new file mode 100644
index 0000000000000000000000000000000000000000..76634c4abfc10dd25267827f279ea89c147ddd79
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/radio-button.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#9A9999;" d="M8,0C3.6,0,0,3.6,0,8s3.6,8,8,8s8-3.6,8-8S12.4,0,8,0z M8,15c-3.9,0-7-3.1-7-7s3.1-7,7-7s7,3.1,7,7
+	S11.9,15,8,15z"/>
+<path style="fill:#FFFFFF;" d="M8,1C4.1,1,1,4.1,1,8s3.1,7,7,7s7-3.1,7-7S11.9,1,8,1z M8,12c-2.2,0-4-1.8-4-4s1.8-4,4-4s4,1.8,4,4
+	S10.2,12,8,12z"/>
+<path style="fill:#676767;" d="M8,4c2.2,0,4,1.8,4,4s-1.8,4-4,4s-4-1.8-4-4S5.8,4,8,4z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/remove.gif b/typo3/sysext/form/Resources/Public/Images/remove.gif
deleted file mode 100644
index 04999ad062c2e9cd077e8f9b5d4b3453fcb6615a..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/remove.gif and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/single-select.svg b/typo3/sysext/form/Resources/Public/Images/single-select.svg
new file mode 100644
index 0000000000000000000000000000000000000000..961bfe934a36292711a15d5153debd940fbb4852
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/single-select.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#FFFFFF;" d="M1,1v14h14V1H1z M8,12.9L4.5,9.4l0.7-0.7L8,11.5l2.8-2.8l0.7,0.7L8,12.9z M10.8,7.3L8,4.4L5.2,7.3
+	L4.5,6.6l2.8-2.9L8,3l0.7,0.7l2.8,2.9L10.8,7.3z"/>
+<path style="fill:#9A9999;" d="M15,0H1H0v1v14v1h1h14h1v-1V1V0H15z M15,15H1V1h14V15z"/>
+<path style="fill:#676767;" d="M8,4.4l2.8,2.9l0.7-0.7L8.7,3.7L8,3L7.3,3.7L4.5,6.6l0.7,0.7L8,4.4z M8,11.5L5.2,8.7L4.5,9.4L8,12.9
+	l3.5-3.5l-0.7-0.7L8,11.5z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/static-text.svg b/typo3/sysext/form/Resources/Public/Images/static-text.svg
new file mode 100644
index 0000000000000000000000000000000000000000..13cc3f62aafa606602cc2c779cdcb03aa0959311
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/static-text.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#FFFFFF;" d="M1,1v14h14V1H1z M14,14H2v-1h12V14z M14,12H2v-1h12V12z M14,10H2V9h12V10z M14,8H2V7h12V8z M14,6H2V5
+	h12V6z M14,4H2V2h12V4z"/>
+<path style="fill:#9A9999;" d="M15,0H1H0v1v14v1h1h14h1v-1V1V0H15z M15,15H1V1h14V15z"/>
+<path style="fill:#676767;" d="M2,2v2h12V2H2z M2,6h12V5H2V6z M2,8h12V7H2V8z M2,10h12V9H2V10z M2,12h12v-1H2V12z M2,14h12v-1H2V14z
+	"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/submit-trigger.gif b/typo3/sysext/form/Resources/Public/Images/submit-trigger.gif
deleted file mode 100644
index fa0230f86d5a4b76689349300a6883d8619afebf..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/submit-trigger.gif and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/summary-page.svg b/typo3/sysext/form/Resources/Public/Images/summary-page.svg
new file mode 100644
index 0000000000000000000000000000000000000000..51ca03e70e7d1c37da6236f36c3829d972157081
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/summary-page.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#79A548;" d="M8.8,6.8L7.6,8L7.1,7.5L6.8,7.8l0.8,0.8l0,0l0.3-0.3l1.2-1.2L8.8,6.8z M8.8,9.2l-1.2,1.3L7.1,10
+	l-0.3,0.3l0.8,0.8l0,0l0.3-0.3l1.2-1.2L8.8,9.2z M8.8,11.8L7.6,13l-0.5-0.5l-0.3,0.3l0.8,0.8l0,0l0.3-0.3l1.2-1.2L8.8,11.8z"/>
+<path style="fill:#FFFFFF;" d="M3,1v14h2V5h4V1H3z M10,4V1.4L12.6,4H10z M6,15h9V6H6V15z M9.2,7.4h5v1.2h-5V7.4z M9.2,9.9h5v1.2h-5
+	V9.9z M9.2,12.4h5v1.2h-5V12.4z M7.1,7.5L7.6,8l1.2-1.2l0.3,0.3L7.9,8.3L7.6,8.6L6.8,7.8L7.1,7.5z M7.1,10l0.5,0.5l1.2-1.3l0.3,0.4
+	l-1.2,1.2l-0.3,0.3l-0.8-0.8L7.1,10z M7.1,12.5L7.6,13l1.2-1.2l0.3,0.3l-1.2,1.2l-0.3,0.3l-0.8-0.8L7.1,12.5z"/>
+<path style="fill:#676767;" d="M9.2,7.4h5v1.2h-5V7.4z M9.2,9.9h5v1.2h-5V9.9z M9.2,12.4h5v1.2h-5V12.4z M15,6v9H6V6H15 M16,5H5v11
+	h11V5z"/>
+<path style="fill:#999999;" d="M3,15V1h6v4h4h1V4l-4-4H2v16h3v-1H3z M10,1.4L12.6,4H10V1.4z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/text.svg b/typo3/sysext/form/Resources/Public/Images/text.svg
new file mode 100644
index 0000000000000000000000000000000000000000..db92ec02974d967f251d18762d80619e111c9fb7
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/text.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#FFFFFF;" d="M1,9.5h3v-3H1V9.5z M5,6.5v3h10v-3H5z"/>
+<path style="fill:#9A9999;" d="M0,10.5h4v-1H1v-3h3v-1H0V10.5z M5,5.5v1h10v3H5v1h11v-5H5z"/>
+<polygon style="fill:#676767;" points="6.5,4.5 6.5,3.5 5,3.5 4,3.5 2.5,3.5 2.5,4.5 4,4.5 4,11.5 2.5,11.5 2.5,12.5 4,12.5 5,12.5 
+	6.5,12.5 6.5,11.5 5,11.5 5,4.5 "/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/textarea.svg b/typo3/sysext/form/Resources/Public/Images/textarea.svg
new file mode 100644
index 0000000000000000000000000000000000000000..4efeb102c7f17c54f1b338546a97b7f9f55454d6
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/textarea.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#FFFFFF;" d="M1,1v14h14V1H1z M10,13H2v-1h8V13z M14,11H2v-1h12V11z M14,9H2V8h12V9z M14,7H2V6h12V7z M14,5H2V4h12
+	V5z M14,3H2V2h12V3z"/>
+<path style="fill:#9A9999;" d="M15,0H1H0v1v14v1h1h14h1v-1V1V0H15z M15,15H1V1h14V15z"/>
+<path style="fill:#676767;" d="M2,2v1h12V2H2z M2,5h12V4H2V5z M2,7h12V6H2V7z M2,9h12V8H2V9z M2,11h12v-1H2V11z M2,13h8v-1H2V13z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/Images/tooltip.png b/typo3/sysext/form/Resources/Public/Images/tooltip.png
deleted file mode 100644
index 2dcfe228d861ba9ff9b5df20a85f9c59d0ce1c1e..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/tooltip.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/ui-button-default.png b/typo3/sysext/form/Resources/Public/Images/ui-button-default.png
deleted file mode 100644
index 0c78dc6ae4fcb2d51a59243eecc9e1bf8892a055..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/ui-button-default.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/ui-button.png b/typo3/sysext/form/Resources/Public/Images/ui-button.png
deleted file mode 100644
index d13064cc74d7d1ceb080435719f78c55c40aa876..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/ui-button.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/ui-check-box.png b/typo3/sysext/form/Resources/Public/Images/ui-check-box.png
deleted file mode 100644
index 45a96e975fd5b5270ae80f94b13670217eb88742..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/ui-check-box.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/ui-check-boxes.png b/typo3/sysext/form/Resources/Public/Images/ui-check-boxes.png
deleted file mode 100644
index 7ed6644b6af67d114574a195802fe7f05a1392da..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/ui-check-boxes.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/ui-combo-box.png b/typo3/sysext/form/Resources/Public/Images/ui-combo-box.png
deleted file mode 100644
index f4c3e2e1c4b30d3cc136d60d778eada7249381ed..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/ui-combo-box.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/ui-group-box.png b/typo3/sysext/form/Resources/Public/Images/ui-group-box.png
deleted file mode 100644
index 3f9e7eb1aacb916344a3d552c42d878ffde9001a..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/ui-group-box.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/ui-labels.png b/typo3/sysext/form/Resources/Public/Images/ui-labels.png
deleted file mode 100644
index f4b0c418d07125d0d10c74ed1d5f64a753914531..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/ui-labels.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/ui-radio-button.png b/typo3/sysext/form/Resources/Public/Images/ui-radio-button.png
deleted file mode 100644
index cbdb9223daeca3226b7aad1f835d34e280363726..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/ui-radio-button.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/ui-radio-buttons.png b/typo3/sysext/form/Resources/Public/Images/ui-radio-buttons.png
deleted file mode 100644
index 4face34b24a76003aab6cf739e1d9c5c36514d08..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/ui-radio-buttons.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/ui-scroll-pane-text.png b/typo3/sysext/form/Resources/Public/Images/ui-scroll-pane-text.png
deleted file mode 100644
index 85400c6120782dce91b6b472146bd451ddc8f188..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/ui-scroll-pane-text.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/ui-text-field-hidden.png b/typo3/sysext/form/Resources/Public/Images/ui-text-field-hidden.png
deleted file mode 100644
index 715e18d06c97240bd13dd813246348f8e66f5eaa..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/ui-text-field-hidden.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/ui-text-field-password.png b/typo3/sysext/form/Resources/Public/Images/ui-text-field-password.png
deleted file mode 100644
index fd0fa5a65549a2d27d28d7c372ae87224fc5422b..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/ui-text-field-password.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/ui-text-field.png b/typo3/sysext/form/Resources/Public/Images/ui-text-field.png
deleted file mode 100644
index bd818025869b33833d0178331322f1c19263d422..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/ui-text-field.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/user-silhouette.png b/typo3/sysext/form/Resources/Public/Images/user-silhouette.png
deleted file mode 100644
index 6205ff18ad0d23bf2c0a310c28473c22881a190e..0000000000000000000000000000000000000000
Binary files a/typo3/sysext/form/Resources/Public/Images/user-silhouette.png and /dev/null differ
diff --git a/typo3/sysext/form/Resources/Public/Images/validator.svg b/typo3/sysext/form/Resources/Public/Images/validator.svg
new file mode 100644
index 0000000000000000000000000000000000000000..5b1ed6a243b6dbb24df68cd3b56102bb57cf7674
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/Images/validator.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<path style="fill:#0078e6;" d="M14,0H2H1v1v7c0,4.5,6.5,7.7,6.8,7.8L8,15.9l0.2-0.1C8.5,15.7,15,12.4,15,8V1V0H14z M8,14.8
+	C6.9,14.2,2,11.5,2,8V1h12v7C14,11.4,9.1,14.2,8,14.8z"/>
+<path style="fill:#FFFFFF;" d="M14,8V1H8v13.8C9.1,14.2,14,11.4,14,8z"/>
+<path style="fill:#0078e6;" d="M2,1v7c0,3.5,4.9,6.2,6,6.8V1H2z"/>
+</svg>
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor.js b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor.js
new file mode 100644
index 0000000000000000000000000000000000000000..adecd027bd496d27c12949dddd37cd4160894463
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor.js
@@ -0,0 +1,1114 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/Form/Backend/FormEditor
+ */
+define(['jquery',
+        'TYPO3/CMS/Form/Backend/FormEditor/Core',
+        ], function($, core) {
+        'use strict';
+
+    /**
+     * Return a static method named "getInstance".
+     * Use this method to create the formeditor app.
+     */
+    return (function(_core) {
+
+        /**
+         * @private
+         *
+         * Hold the instance (Singleton Pattern)
+         */
+        var _formEditorInstance = null;
+
+        /**
+         * @public
+         *
+         * @param object _configuration
+         * @param object _mediator
+         * @param object _viewModel
+         * @return object
+         */
+        function FormEditor(_configuration, _mediator, _viewModel) {
+
+            /**
+             * @private
+             *
+             * @var bool
+             */
+            var _isRunning = false;
+
+            /**
+             * @private
+             *
+             * @var bool
+             */
+            var _unsavedContent = false;
+
+            /**
+             * @private
+             *
+             * @var bool
+             */
+            var _previewMode = false;
+
+            /**
+             * @public
+             *
+             * @return object
+             */
+            function getPublisherSubscriber() {
+                return _core.getPublisherSubscriber();
+            };
+
+            /**
+             * @public
+             *
+             * @return void
+             */
+            function _saveApplicationState() {
+
+                _getApplicationStateStack().addAndReset({
+                    formDefinition: _getApplicationStateStack().getCurrentState('formDefinition').clone(),
+                    currentlySelectedPageIndex: _getApplicationStateStack().getCurrentState('currentlySelectedPageIndex'),
+                    currentlySelectedFormElementIdentifierPath: _getApplicationStateStack().getCurrentState('currentlySelectedFormElementIdentifierPath')
+                });
+            };
+
+            /**
+             * @public
+             *
+             * @return void
+             */
+            function undoApplicationState() {
+                _getApplicationStateStack().incrementCurrentStackPointer();
+            };
+
+            /**
+             * @public
+             *
+             * @return void
+             */
+            function redoApplicationState() {
+                _getApplicationStateStack().decrementCurrentStackPointer();
+            };
+
+            /**
+             * @public
+             *
+             * @return int
+             */
+            function getMaximalApplicationStates() {
+                return _getApplicationStateStack().getMaximalStackSize();
+            };
+
+            /**
+             * @public
+             *
+             * @return int
+             */
+            function getCurrentApplicationStates() {
+                return _getApplicationStateStack().getCurrentStackSize();
+            };
+
+            /**
+             * @public
+             *
+             * @return int
+             */
+            function getCurrentApplicationStatePosition() {
+                return _getApplicationStateStack().getCurrentStackPointer();
+            };
+
+            /**
+             * @public
+             *
+             * @param string type
+             * @return object
+             * @throws 1475378543
+             */
+            function getRunningAjaxRequest(type) {
+                assert(getUtility().isNonEmptyString(type), 'Invalid parameter "type"', 1475378543);
+                return _core.getRunningAjaxRequest(type);
+            };
+
+            /**
+             * @public
+             *
+             * @return object
+             */
+            function getUtility() {
+                return _core.getUtility();
+            };
+
+            /**
+             * @public
+             *
+             * @param mixed test
+             * @param string message
+             * @param int messageCode
+             * @return void
+             */
+            function assert(test, message, messageCode) {
+                getUtility().assert(test, message, messageCode);
+            };
+
+            /**
+             * @public
+             *
+             * @param string propertyPath
+             * @param string collectionElementIdentifier
+             * @param string collectionName
+             * @param object formElement
+             * @param boolean allowEmptyReturnValue
+             * @return string
+             */
+            function buildPropertyPath(propertyPath, collectionElementIdentifier, collectionName, formElement, allowEmptyReturnValue) {
+                if (getUtility().isUndefinedOrNull(formElement)) {
+                    formElement = getCurrentlySelectedFormElement();
+                }
+                formElement = _getRepository().findFormElement(formElement);
+                return getUtility().buildPropertyPath(propertyPath, collectionElementIdentifier, collectionName, formElement, allowEmptyReturnValue);
+            };
+
+            /**
+             * @public
+             *
+             * @param string validatorIdentifier
+             * @param function func
+             * @return void
+             */
+            function addPropertyValidationValidator(validatorIdentifier, func) {
+                _getPropertyValidationService().addValidator(validatorIdentifier, func);
+            };
+
+            /**
+             * @public
+             *
+             * @param string propertyPath
+             * @return object
+             */
+            function validateCurrentlySelectedFormElementProperty(propertyPath) {
+                return validateFormElementProperty(
+                    getCurrentlySelectedFormElement(),
+                    propertyPath
+                );
+            };
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @param string propertyPath
+             * @return object
+             */
+            function validateFormElementProperty(formElement, propertyPath) {
+                formElement = _getRepository().findFormElement(formElement);
+                return _getPropertyValidationService().validateFormElementProperty(formElement, propertyPath);
+            };
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @return object
+             */
+            function validateFormElement(formElement) {
+                formElement = _getRepository().findFormElement(formElement);
+                return _getPropertyValidationService().validateFormElement(formElement);
+            };
+
+            /**
+             * @public
+             *
+             * @param object validationResults
+             * @return boolean
+             */
+            function validationResultsHasErrors(validationResults) {
+                return _getPropertyValidationService().validationResultsHasErrors(validationResults);
+            };
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @param boolean returnAfterFirstMatch
+             * @return object
+             */
+            function validateFormElementRecursive(formElement, returnAfterFirstMatch) {
+                formElement = _getRepository().findFormElement(formElement);
+                return _getPropertyValidationService().validateFormElementRecursive(formElement, returnAfterFirstMatch);
+            };
+
+            /**
+             * @public
+             *
+             * @param bool unsavedContent
+             * @return void
+             * @throws 1475378544
+             */
+            function setUnsavedContent(unsavedContent) {
+                assert('boolean' === $.type(unsavedContent), 'Invalid parameter "unsavedContent"', 1475378544);
+                _unsavedContent = unsavedContent;
+            };
+
+            /**
+             * @public
+             *
+             * @return boolean
+             */
+            function getUnsavedContent() {
+                return _unsavedContent;
+            };
+
+            /**
+             * @public
+             *
+             * @return object
+             */
+            function getRootFormElement() {
+                return _getRepository().getRootFormElement();
+            };
+
+            /**
+             * @public
+             *
+             * @return string
+             */
+            function getCurrentlySelectedFormElement() {
+                return _getRepository().findFormElementByIdentifierPath(_getApplicationStateStack().getCurrentState('currentlySelectedFormElementIdentifierPath'));
+            };
+
+            /**
+             * @public
+             *
+             * @param string|object formElement
+             * @param boolean doNotRefreshCurrentlySelectedPageIndex
+             * @return void
+             * @publish core/currentlySelectedFormElementChanged
+             */
+            function setCurrentlySelectedFormElement(formElement, doNotRefreshCurrentlySelectedPageIndex) {
+                doNotRefreshCurrentlySelectedPageIndex = !!doNotRefreshCurrentlySelectedPageIndex;
+
+                formElement = _getRepository().findFormElement(formElement);
+                _getApplicationStateStack().setCurrentState('currentlySelectedFormElementIdentifierPath', formElement.get('__identifierPath'));
+
+                if (!doNotRefreshCurrentlySelectedPageIndex) {
+                    refreshCurrentlySelectedPageIndex();
+                }
+                getPublisherSubscriber().publish('core/currentlySelectedFormElementChanged', [formElement]);
+            };
+
+            /**
+             * @public
+             *
+             * @param string identifierPath
+             * @return object
+             * @throws 1475378545
+             */
+            function getFormElementByIdentifierPath(identifierPath) {
+                assert(getUtility().isNonEmptyString(identifierPath), 'Invalid parameter "identifierPath"', 1475378545);
+                return _getRepository().findFormElementByIdentifierPath(identifierPath);
+            };
+
+            /**
+             * @public
+             *
+             * @param string identifierPath
+             * @return bool
+             */
+            function isFormElementIdentifierUsed(formElementIdentifier) {
+                return _getRepository().isFormElementIdentifierUsed(formElementIdentifier);
+            }
+
+            /**
+             * @public
+             *
+             * @param string formElementType
+             * @param string|object referenceFormElement
+             * @param boolean disablePublishersOnSet
+             * @return object
+             */
+            function createAndAddFormElement(formElementType, referenceFormElement, disablePublishersOnSet) {
+                var formElement;
+                formElement = addFormElement(createFormElement(formElementType, disablePublishersOnSet), referenceFormElement, disablePublishersOnSet);
+                formElement.set('renderables', formElement.get('renderables'));
+                return formElement;
+            };
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @param string|object referenceFormElement
+             * @param boolean disablePublishersOnSet
+             * @return object
+             * @throws 1475434337
+             */
+            function addFormElement(formElement, referenceFormElement, disablePublishersOnSet) {
+                _saveApplicationState();
+
+                if (getUtility().isUndefinedOrNull(referenceFormElement)) {
+                    referenceFormElement = getCurrentlySelectedFormElement();
+                }
+                referenceFormElement = _getRepository().findFormElement(referenceFormElement);
+                assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475434337);
+                return _getRepository().addFormElement(formElement, referenceFormElement, true, disablePublishersOnSet);
+            };
+
+            /**
+             * @public
+             *
+             * @param string formElementType
+             * @param boolean disablePublishersOnSet
+             * @return object
+             * @throws 1475434336
+             * @throws 1475435857
+             */
+            function createFormElement(formElementType, disablePublishersOnSet) {
+                var formElementDefinition, identifier;
+                assert(getUtility().isNonEmptyString(formElementType), 'Invalid parameter "formElementType"', 1475434336);
+
+                identifier = _getRepository().getNextFreeFormElementIdentifier(formElementType);
+                formElementDefinition = getFormElementDefinitionByType(formElementType);
+                return _getFactory().createFormElement({
+                    type: formElementType,
+                    identifier: identifier,
+                    label: formElementDefinition['label'] || formElementType
+                }, undefined, undefined, undefined, disablePublishersOnSet);
+            };
+
+            /**
+             * @public
+             *
+             * @param string|object formElementToRemove
+             * @param boolean disablePublishersOnSet
+             * @return object
+             */
+            function removeFormElement(formElementToRemove, disablePublishersOnSet) {
+                var parentFormElement;
+                _saveApplicationState();
+
+                formElementToRemove = _getRepository().findFormElement(formElementToRemove);
+                parentFormElement = formElementToRemove.get('__parentRenderable');
+                _getRepository().removeFormElement(formElementToRemove, true, disablePublishersOnSet);
+                return parentFormElement;
+            };
+
+            /**
+             * @public
+             *
+             * @param string|object formElementToMove
+             * @param string position
+             * @param string|object referenceFormElement
+             * @param boolean disablePublishersOnSet
+             * @return string
+             * @throws 1475378551
+             */
+            function moveFormElement(formElementToMove, position, referenceFormElement, disablePublishersOnSet) {
+                _saveApplicationState();
+
+                formElementToMove = _getRepository().findFormElement(formElementToMove);
+                referenceFormElement = _getRepository().findFormElement(referenceFormElement);
+
+                assert('after' === position || 'before' === position || 'inside' === position, 'Invalid position "' + position + '"', 1475378551);
+
+                formElementToMove = _getRepository().moveFormElement(formElementToMove, position, referenceFormElement, true);
+                disablePublishersOnSet = !!disablePublishersOnSet;
+                if (!disablePublishersOnSet) {
+                    formElementToMove.get('__parentRenderable').set('renderables', formElementToMove.get('__parentRenderable').get('renderables'));
+                }
+                return formElementToMove;
+            };
+
+            /**
+             * @public
+             *
+             * @param string collectionElementIdentifier
+             * @param string collectionName
+             * @param string formElement
+             * @return object (dereferenced)
+             * @throws 1475378555
+             * @throws 1475378556
+             * @throws 1475446108
+             */
+            function getPropertyCollectionElementConfiguration(collectionElementIdentifier, collectionName, formElement) {
+                var collection, collectionElement, formElementDefinition;
+                if (getUtility().isUndefinedOrNull(formElement)) {
+                    formElement = getCurrentlySelectedFormElement();
+                }
+                formElement = _getRepository().findFormElement(formElement);
+
+                assert(getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378555);
+                assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378556);
+
+                formElementDefinition = getFormElementDefinitionByType(formElement.get('type'));
+                collection = formElementDefinition['propertyCollections'][collectionName];
+                assert(!getUtility().isUndefinedOrNull(collection), 'Invalid collection name "' + collectionName + '"', 1475446108);
+                collectionElement = _getRepository().findCollectionElementByIdentifierPath(collectionElementIdentifier, collection);
+
+                return $.extend(true, {}, collectionElement);
+            };
+
+            /**
+             * @public
+             *
+             * @param string collectionElementIdentifier
+             * @param string collectionName
+             * @param string formElement
+             * @return int
+             * @throws 1475378557
+             * @throws 1475378558
+             */
+            function getIndexFromPropertyCollectionElement(collectionElementIdentifier, collectionName, formElement) {
+                var indexFromPropertyCollectionElement;
+                if (getUtility().isUndefinedOrNull(formElement)) {
+                    formElement = getCurrentlySelectedFormElement();
+                }
+                formElement = _getRepository().findFormElement(formElement);
+
+                assert(getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378557);
+                assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378558);
+
+                indexFromPropertyCollectionElement = _getRepository().getIndexFromPropertyCollectionElementByIdentifier(
+                    collectionElementIdentifier,
+                    collectionName,
+                    formElement
+                );
+
+                return indexFromPropertyCollectionElement;
+            };
+
+            /**
+             * @public
+             *
+             * @param string collectionElementIdentifier
+             * @param string collectionName
+             * @param object formElement
+             * @param object collectionElementConfiguration
+             * @param string referenceCollectionElementIdentifier
+             * @return object
+             */
+            function createAndAddPropertyCollectionElement(collectionElementIdentifier, collectionName, formElement, collectionElementConfiguration, referenceCollectionElementIdentifier) {
+                return addPropertyCollectionElement(createPropertyCollectionElement(collectionElementIdentifier, collectionName, collectionElementConfiguration), collectionName, formElement, referenceCollectionElementIdentifier);
+            };
+
+            /**
+             * @public
+             *
+             * @param object collectionElement
+             * @param string collectionName
+             * @param string|object formElement
+             * @param string referenceCollectionElementIdentifier
+             * @return object
+             * @throws 1475443300
+             * @throws 1475443301
+             */
+            function addPropertyCollectionElement(collectionElement, collectionName, formElement, referenceCollectionElementIdentifier) {
+                var collection;
+                _saveApplicationState();
+
+                if (getUtility().isUndefinedOrNull(formElement)) {
+                    formElement = getCurrentlySelectedFormElement();
+                }
+                formElement = _getRepository().findFormElement(formElement);
+
+                assert('object' === $.type(collectionElement), 'Invalid parameter "collectionElement"', 1475443301);
+                assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475443300);
+
+                if (getUtility().isUndefinedOrNull(referenceCollectionElementIdentifier)) {
+                    collection = formElement.get(collectionName);
+                    if ('array' === $.type(collection) && collection.length > 0) {
+                        referenceCollectionElementIdentifier = collection[collection.length - 1]['identifier'];
+                    }
+                }
+
+                return _getRepository().addPropertyCollectionElement(
+                    collectionElement,
+                    collectionName,
+                    formElement,
+                    referenceCollectionElementIdentifier,
+                    false
+                );
+            };
+
+            /**
+             * @public
+             *
+             * @param string collectionElementIdentifier
+             * @param string collectionName
+             * @param object collectionElementConfiguration
+             * @return void
+             * @throws 1475378559
+             * @throws 1475378560
+             */
+            function createPropertyCollectionElement(collectionElementIdentifier, collectionName, collectionElementConfiguration) {
+                assert(getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378559);
+                assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378560);
+                if ('object' !== $.type(collectionElementConfiguration)) {
+                    collectionElementConfiguration = {};
+                }
+
+                return _getFactory().createPropertyCollectionElement(collectionElementIdentifier, collectionElementConfiguration, collectionName);
+            };
+
+            /**
+             * @public
+             *
+             * @param string collectionElementIdentifier
+             * @param string collectionName
+             * @param string formElement
+             * @param bool disablePublishersOnSet
+             * @return void
+             * @throws 1475378561
+             * @throws 1475378562
+             */
+            function removePropertyCollectionElement(collectionElementIdentifier, collectionName, formElement, disablePublishersOnSet) {
+                _saveApplicationState();
+
+                if (getUtility().isUndefinedOrNull(formElement)) {
+                    formElement = getCurrentlySelectedFormElement();
+                }
+                formElement = _getRepository().findFormElement(formElement);
+
+                assert(getUtility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475378561);
+                assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475378562);
+
+                _getRepository().removePropertyCollectionElementByIdentifier(
+                    formElement,
+                    collectionElementIdentifier,
+                    collectionName,
+                    true
+                );
+
+                disablePublishersOnSet = !!disablePublishersOnSet;
+                if (!disablePublishersOnSet) {
+                    getPublisherSubscriber().publish('core/formElement/somePropertyChanged', ['__fakeProperty']);
+                }
+            };
+
+            /**
+             * @public
+             *
+             * @param string collectionElementToMove
+             * @param string position
+             * @param string referenceCollectionElement
+             * @param string collectionName
+             * @param object formElement
+             * @param boolean disablePublishersOnSet
+             * @return string
+             * @throws 1477404352
+             * @throws 1477404353
+             * @throws 1477404354
+             * @throws 1477404355
+             */
+            function movePropertyCollectionElement(collectionElementToMove, position, referenceCollectionElement, collectionName, formElement, disablePublishersOnSet) {
+                _saveApplicationState();
+
+                formElement = _getRepository().findFormElement(formElement);
+
+                assert('string' === $.type(collectionElementToMove), 'Invalid parameter "collectionElementToMove"', 1477404352);
+                assert('string' === $.type(referenceCollectionElement), 'Invalid parameter "referenceCollectionElement"', 1477404353);
+                assert('after' === position || 'before' === position, 'Invalid position "' + position + '"', 1477404354);
+                assert(getUtility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1477404355);
+
+                return _getRepository().movePropertyCollectionElement(collectionElementToMove, position, referenceCollectionElement, collectionName, formElement, disablePublishersOnSet);
+            };
+
+            /**
+             * @public
+             *
+             * @param string elementType
+             * @param string formElementDefinitionKey
+             * @returnmixed
+             * @throws 1475378563
+             */
+            function getFormElementDefinitionByType(elementType, formElementDefinitionKey) {
+                var formElementDefinition;
+                assert(getUtility().isNonEmptyString(elementType), 'Invalid parameter "elementType"', 1475378563);
+
+                formElementDefinition = _getRepository().getFormEditorDefinition('formElements', elementType);
+
+                if (!getUtility().isUndefinedOrNull(formElementDefinitionKey)) {
+                    formElementDefinition = formElementDefinition[formElementDefinitionKey];
+                }
+
+                if ('object' === $.type(formElementDefinition) || 'array' === $.type(formElementDefinition)) {
+                    return $.extend(true, {}, formElementDefinition);
+                } else {
+                    return formElementDefinition;
+                }
+            };
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @param string formElementDefinitionKey
+             * @return mixed
+             */
+            function getFormElementDefinition(formElement, formElementDefinitionKey) {
+                formElement = _getRepository().findFormElement(formElement);
+                return getFormElementDefinitionByType(formElement.get('type'), formElementDefinitionKey);
+            };
+
+            /**
+             * @public
+             *
+             * @param string collectionName
+             * @param string collectionElementIdentifier
+             * @return mixed
+             */
+            function getFormEditorDefinition(definitionName, subject) {
+                return _getRepository().getFormEditorDefinition(definitionName, subject);
+            };
+
+            /**
+             * @public
+             *
+             * @param string validatorIdentifier
+             * @return object (dereferenced)
+             * @throws 1475672362
+             */
+            function getFormElementPropertyValidatorDefinition(validatorIdentifier) {
+                var validatorDefinition;
+                assert(getUtility().isNonEmptyString(validatorIdentifier), 'Invalid parameter "validatorIdentifier"', 1475672362);
+
+                validatorDefinition = _getRepository().getFormEditorDefinition('formElementPropertyValidators', validatorIdentifier);
+                return $.extend(true, {}, validatorDefinition);
+            };
+
+            /**
+             * @public
+             *
+             * @return int
+             */
+            function getCurrentlySelectedPageIndex() {
+                return _getApplicationStateStack().getCurrentState('currentlySelectedPageIndex');
+            };
+
+            /**
+             * @public
+             *
+             * @return void
+             */
+            function refreshCurrentlySelectedPageIndex() {
+                _getApplicationStateStack().setCurrentState('currentlySelectedPageIndex', getPageIndexFromFormElement(getCurrentlySelectedFormElement()));
+            };
+
+            /**
+             * @public
+             *
+             * @return object
+             * @throws 1477786068
+             */
+            function getCurrentlySelectedPage() {
+                var currentPage;
+
+                currentPage = _getRepository().getRootFormElement().get('renderables')[getCurrentlySelectedPageIndex()];
+                assert('object' === $.type(currentPage), 'No page found', 1477786068);
+                return currentPage;
+            };
+
+            /**
+             * @public
+             *
+             * @return object
+             */
+            function getLastTopLevelElementOnCurrentPage() {
+                var lastRenderable, renderables;
+
+                renderables = getCurrentlySelectedPage().get('renderables');
+                if (getUtility().isUndefinedOrNull(renderables)) {
+                    return undefined;
+                }
+                lastRenderable = renderables[renderables.length - 1];
+                return lastRenderable;
+            };
+
+            /**
+             * @public
+             *
+             * @param object
+             * @return object
+             */
+            function getLastFormElementWithinParentFormElement(formElement) {
+                var lastElement;
+
+                formElement = _getRepository().findFormElement(formElement);
+                if (formElement.get('__identifierPath') === getRootFormElement().get('__identifierPath')) {
+                    return formElement;
+                }
+                return formElement.get('__parentRenderable').get('renderables')[formElement.get('__parentRenderable').get('renderables').length - 1];
+            };
+
+            /**
+             * @public
+             *
+             * @param object
+             * @return int
+             */
+            function getPageIndexFromFormElement(formElement) {
+                formElement = _getRepository().findFormElement(formElement);
+
+                return _getRepository().getIndexForEnclosingCompositeFormElementWhichIsOnTopLevelForFormElement(
+                    formElement
+                );
+            };
+
+            /**
+             * @public
+             *
+             * @return void
+             */
+            function renderCurrentFormPage() {
+                renderFormPage(getCurrentlySelectedPageIndex());
+            };
+
+            /**
+             * @public
+             *
+             * @param int pageIndex
+             * @return void
+             * @throws 1475446442
+             */
+            function renderFormPage(pageIndex) {
+                assert('number' === $.type(pageIndex), 'Invalid parameter "pageIndex"', 1475446442);
+                _getDataBackend().renderFormDefinitionPage(pageIndex);
+            };
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @return object|null
+             */
+            function findEnclosingCompositeFormElementWhichIsNotOnTopLevel(formElement) {
+                return _getRepository().findEnclosingCompositeFormElementWhichIsNotOnTopLevel(
+                    _getRepository().findFormElement(formElement)
+                );
+            };
+
+            /**
+             * @public
+             *
+             * @return boolean
+             */
+            function isRootFormElementSelected() {
+                return (getCurrentlySelectedFormElement().get('__identifierPath') === getRootFormElement().get('__identifierPath'));
+            };
+
+            /**
+             * @public
+             *
+             * @return object
+             */
+            function getViewModel() {
+                return _viewModel;
+            };
+
+            /**
+             * @public
+             *
+             * @return void
+             */
+            function saveFormDefinition() {
+                _getDataBackend().saveFormDefinition();
+            };
+
+            /**
+             * @private
+             *
+             * @return object
+             */
+            function _getDataBackend() {
+                return _core.getDataBackend();
+            };
+
+            /**
+             * @private
+             *
+             * @return object
+             */
+            function _getFactory() {
+                return _core.getFactory();
+            };
+
+            /**
+             * @private
+             *
+             * @return object
+             */
+            function _getRepository() {
+                return _core.getRepository();
+            };
+
+            /**
+             * @private
+             *
+             * @return object
+             */
+            function _getPropertyValidationService() {
+                return _core.getPropertyValidationService();
+            };
+
+            /**
+             * @public
+             *
+             * @return object
+             */
+            function _getApplicationStateStack() {
+                return _core.getApplicationStateStack();
+            };
+
+            /**
+             * @private
+             *
+             * @return void
+             * @publish ajax/beforeSend
+             * @publish ajax/complete
+             */
+            function _ajaxSetup() {
+                $.ajaxSetup({
+                    beforeSend: function() {
+                        getPublisherSubscriber().publish('ajax/beforeSend');
+                    },
+                    complete: function() {
+                        getPublisherSubscriber().publish('ajax/complete');
+                    }
+                });
+            };
+
+            /**
+             * @private
+             *
+             * @param object endpoints
+             * @param string prototypeName
+             * @param string formPersistenceIdentifier
+             * @return void
+             * @throws 1475379748
+             * @throws 1475379749
+             * @throws 1475927876
+             */
+            function _dataBackendSetup(endpoints, prototypeName, formPersistenceIdentifier) {
+                assert('object' === $.type(endpoints), 'Invalid parameter "endpoints"', 1475379748);
+                assert(getUtility().isNonEmptyString(prototypeName), 'Invalid parameter "prototypeName"', 1475927876);
+                assert(getUtility().isNonEmptyString(formPersistenceIdentifier), 'Invalid parameter "formPersistenceIdentifier"', 1475379749);
+
+                _core.getDataBackend().setEndpoints(endpoints);
+                _core.getDataBackend().setPrototypeName(prototypeName);
+                _core.getDataBackend().setPersistenceIdentifier(formPersistenceIdentifier);
+            };
+
+            /**
+             * @private
+             *
+             * @param object formEditorDefinitions
+             * @return void
+             * @throws 1475379750
+             */
+            function _repositorySetup(formEditorDefinitions) {
+                assert('object' === $.type(formEditorDefinitions), 'Invalid parameter "formEditorDefinitions"', 1475379750);
+
+                _getRepository().setFormEditorDefinitions(formEditorDefinitions);
+            }
+
+            /**
+             * @private
+             *
+             * @param object additionalViewModelModules
+             * @return void
+             * @throws 1475379752
+             * @throws 1475492374
+             */
+            function _viewSetup(additionalViewModelModules) {
+                assert('function' === $.type(_viewModel.bootstrap), 'The view model does not implement the method "bootstrap"', 1475492374);
+
+                if (!getUtility().isUndefinedOrNull(additionalViewModelModules)) {
+                    assert('array' === $.type(additionalViewModelModules), 'Invalid parameter "additionalViewModelModules"', 1475379752);
+                } else {
+                    additionalViewModelModules = [];
+                }
+                _viewModel.bootstrap(_formEditorInstance, additionalViewModelModules);
+            };
+
+            /**
+             * @private
+             *
+             * @return void
+             * @throws 1475492032
+             */
+            function _mediatorSetup() {
+                assert('function' === $.type(_mediator.bootstrap), 'The mediator does not implement the method "bootstrap"', 1475492032);
+                _mediator.bootstrap(_formEditorInstance, _viewModel);
+            };
+
+            /**
+             * @private
+             *
+             * @param object rootFormElement
+             * @param int maximumUndoSteps
+             * @return void
+             * @throws 1475379751
+             */
+            function _applicationStateStackSetup(rootFormElement, maximumUndoSteps) {
+                assert('object' === $.type(rootFormElement), 'Invalid parameter "rootFormElement"', 1475379751);
+
+                if ('number' !== $.type(maximumUndoSteps)) {
+                    maximumUndoSteps = 10;
+                }
+                _getApplicationStateStack().setMaximalStackSize(maximumUndoSteps);
+
+                _getApplicationStateStack().addAndReset({
+                    currentlySelectedPageIndex: 0,
+                    currentlySelectedFormElementIdentifierPath: rootFormElement['identifier']
+                }, true);
+
+                _getApplicationStateStack().setCurrentState('formDefinition', _getFactory().createFormElement(rootFormElement, undefined, undefined, true));
+            };
+
+            /**
+             * @private
+             *
+             * @return void
+             */
+            function _bootstrap() {
+                _configuration = _configuration || {};
+
+                _mediatorSetup();
+                _ajaxSetup();
+                _dataBackendSetup(_configuration['endpoints'], _configuration['prototypeName'], _configuration['formPersistenceIdentifier']);
+                _repositorySetup(_configuration['formEditorDefinitions']);
+                _applicationStateStackSetup(_configuration['formDefinition'], _configuration['maximumUndoSteps']);
+                setCurrentlySelectedFormElement(_getRepository().getRootFormElement());
+
+                _viewSetup(_configuration['additionalViewModelModules']);
+            };
+
+            /**
+             * @public
+             *
+             * @return TYPO3/CMS/Form/Backend/FormEditor
+             * @throws 1473200696
+             */
+            function run() {
+                if (_isRunning) {
+                    throw 'You can not run the app twice (1473200696)';
+                }
+
+                _bootstrap();
+                _isRunning = true;
+                return this;
+            };
+
+            /**
+             * Publish the public methods.
+             * Implements the "Revealing Module Pattern".
+             */
+            return {
+                getRootFormElement: getRootFormElement,
+
+                createAndAddFormElement: createAndAddFormElement,
+                createFormElement: createFormElement,
+                addFormElement: addFormElement,
+                moveFormElement: moveFormElement,
+                removeFormElement: removeFormElement,
+
+                getCurrentlySelectedFormElement: getCurrentlySelectedFormElement,
+                setCurrentlySelectedFormElement: setCurrentlySelectedFormElement,
+
+                getFormElementByIdentifierPath: getFormElementByIdentifierPath,
+                isFormElementIdentifierUsed: isFormElementIdentifierUsed,
+
+                createAndAddPropertyCollectionElement: createAndAddPropertyCollectionElement,
+                createPropertyCollectionElement: createPropertyCollectionElement,
+                addPropertyCollectionElement: addPropertyCollectionElement,
+                removePropertyCollectionElement: removePropertyCollectionElement,
+                movePropertyCollectionElement: movePropertyCollectionElement,
+                getIndexFromPropertyCollectionElement: getIndexFromPropertyCollectionElement,
+                getPropertyCollectionElementConfiguration: getPropertyCollectionElementConfiguration,
+
+                saveFormDefinition: saveFormDefinition,
+                renderCurrentFormPage: renderCurrentFormPage,
+                renderFormPage: renderFormPage,
+
+                getCurrentlySelectedPageIndex: getCurrentlySelectedPageIndex,
+                refreshCurrentlySelectedPageIndex: refreshCurrentlySelectedPageIndex,
+                getPageIndexFromFormElement: getPageIndexFromFormElement,
+                getCurrentlySelectedPage: getCurrentlySelectedPage,
+                getLastTopLevelElementOnCurrentPage: getLastTopLevelElementOnCurrentPage,
+                findEnclosingCompositeFormElementWhichIsNotOnTopLevel: findEnclosingCompositeFormElementWhichIsNotOnTopLevel,
+                isRootFormElementSelected: isRootFormElementSelected,
+                getLastFormElementWithinParentFormElement: getLastFormElementWithinParentFormElement,
+
+                getFormElementDefinitionByType: getFormElementDefinitionByType,
+                getFormElementDefinition: getFormElementDefinition,
+                getFormElementPropertyValidatorDefinition: getFormElementPropertyValidatorDefinition,
+                getFormEditorDefinition: getFormEditorDefinition,
+
+                getPublisherSubscriber: getPublisherSubscriber,
+                getRunningAjaxRequest: getRunningAjaxRequest,
+
+                setUnsavedContent: setUnsavedContent,
+                getUnsavedContent: getUnsavedContent,
+
+                addPropertyValidationValidator: addPropertyValidationValidator,
+                validateFormElementProperty: validateFormElementProperty,
+                validateCurrentlySelectedFormElementProperty: validateCurrentlySelectedFormElementProperty,
+                validateFormElement: validateFormElement,
+                validateFormElementRecursive: validateFormElementRecursive,
+                validationResultsHasErrors: validationResultsHasErrors,
+
+                getUtility: getUtility,
+                assert: assert,
+                buildPropertyPath: buildPropertyPath,
+
+                getViewModel: getViewModel,
+                undoApplicationState: undoApplicationState,
+                redoApplicationState: redoApplicationState,
+                getMaximalApplicationStates: getMaximalApplicationStates,
+                getCurrentApplicationStates: getCurrentApplicationStates,
+                getCurrentApplicationStatePosition: getCurrentApplicationStatePosition,
+
+                run: run
+            };
+        };
+
+        /**
+         * Emulation of static methods
+         */
+        return {
+            /**
+             * @public
+             * @static
+             *
+             * Implement the "Singleton Pattern".
+             *
+             * Return a singleton instance of a
+             * "FormEditor" object.
+             *
+             * @param object configuration
+             * @param object mediator
+             * @param object viewModel
+             * @return object
+             */
+            getInstance: function(configuration, mediator, viewModel) {
+                if(_formEditorInstance === null) {
+                    _formEditorInstance = new FormEditor(configuration, mediator, viewModel);
+                }
+                return _formEditorInstance;
+            }
+        };
+    })(core);
+});
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/Core.js b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/Core.js
new file mode 100644
index 0000000000000000000000000000000000000000..0fd0b84ba7f22cd5298033fb2ec6537906db4a39
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/Core.js
@@ -0,0 +1,2127 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/Form/Backend/FormEditor/Core
+ */
+define(['jquery'], function($) {
+        'use strict';
+
+    return (function($) {
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _dataBackendEndpoints = {};
+
+        /**
+         * @private
+         *
+         * @var string
+         */
+        var _dataBackendPrototypeName = null;
+
+        /**
+         * @private
+         *
+         * @var string
+         */
+        var _dataBackendPersistenceIdentifier = null;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _publisherSubscriberTopics = {};
+
+        /**
+         * @private
+         *
+         * @var int
+         */
+        var _publisherSubscriberUid = -1;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+         var _repositoryFormEditorDefinitions = {};
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _runningAjaxRequests = [];
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _propertyValidationServiceValidators = {};
+
+        /**
+         * @private
+         *
+         * @var int
+         */
+        var _applicationStateStackSize = 10;
+
+        /**
+         * @private
+         *
+         * @var int
+         */
+        var _applicationStateStackPointer = 0;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _applicationStateStack = [];
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function utility() {
+
+            /**
+             * @public
+             *
+             * @param mixed test
+             * @param string message
+             * @param int messageCode
+             * @return void
+             */
+            function assert(test, message, messageCode) {
+                if ('function' === $.type(test)) {
+                    test = (test() !== false);
+                }
+                if (!test) {
+                    message = message || "Assertion failed";
+                    if (messageCode) {
+                        message = message + ' (' + messageCode + ')';
+                    }
+                    if ('undefined' !== typeof Error) {
+                        throw new Error(message);
+                    }
+                    throw message;
+                }
+            };
+
+            /**
+             * @public
+             *
+             * @param mixed value
+             * @return bool
+             */
+            function isUndefinedOrNull(value) {
+                return ('undefined' === $.type(value) || 'null' === $.type(value));
+            };
+
+            /**
+             * @public
+             *
+             * @param mixed value
+             * @return bool
+             */
+            function isNonEmptyString(value) {
+                return ('string' === $.type(value) && value.length > 0);
+            };
+
+            /**
+             * @public
+             *
+             * @param string propertyPath
+             * @param string collectionElementIdentifier
+             * @param string collectionName
+             * @param object formElement
+             * @param boolean allowEmptyReturnValue
+             * @return string
+             * @throws 1475412569
+             * @throws 1475412570
+             * @throws 1475415988
+             * @throws 1475663210
+             */
+            function buildPropertyPath(propertyPath, collectionElementIdentifier, collectionName, formElement, allowEmptyReturnValue) {
+                var newPropertyPath = '';
+
+                allowEmptyReturnValue = !!allowEmptyReturnValue;
+                if (isNonEmptyString(collectionElementIdentifier) || isNonEmptyString(collectionName)) {
+                    assert(isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475412569);
+                    assert(isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475412570);
+                    newPropertyPath = collectionName + '.' + repository().getIndexFromPropertyCollectionElementByIdentifier(collectionElementIdentifier, collectionName, formElement);
+                } else {
+                    newPropertyPath = '';
+                }
+
+                if (!isUndefinedOrNull(propertyPath)) {
+                    assert(isNonEmptyString(propertyPath), 'Invalid parameter "propertyPath"', 1475415988);
+                    if (isNonEmptyString(newPropertyPath)) {
+                        newPropertyPath = newPropertyPath + '.' + propertyPath;
+                    } else {
+                        newPropertyPath = propertyPath;
+                    }
+                }
+
+                if (!allowEmptyReturnValue) {
+                    assert(isNonEmptyString(newPropertyPath), 'The property path could not be resolved', 1475663210);
+                }
+                return newPropertyPath;
+            };
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @return object
+             * @throws 1475377782
+             */
+            function convertToSimpleObject(formElement) {
+                var childFormElements, simpleObject, objectData;
+                assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475377782);
+
+                simpleObject = {};
+                objectData = ('function' === $.type(formElement.getObjectData)) ? formElement.getObjectData() : formElement;
+                childFormElements = objectData['renderables'];
+                delete objectData['renderables'];
+
+                for (var key in objectData) {
+                    if (!objectData.hasOwnProperty(key)) {
+                        continue;
+                    }
+                    var value = objectData[key];
+                    if (key.match(/^__/)) {
+                        continue;
+                    }
+
+                    if ('object' === $.type(value)) {
+                        simpleObject[key] = convertToSimpleObject(value);
+                    } else if ('function' !== $.type(value) && 'undefined' !== $.type(value)) {
+                        simpleObject[key] = value;
+                    }
+                }
+
+                if ('array' === $.type(childFormElements)) {
+                    simpleObject['renderables'] = [];
+                    for (var i = 0, len = childFormElements.length; i < len; ++i) {
+                        simpleObject['renderables'].push(convertToSimpleObject(childFormElements[i]));
+                    }
+                }
+
+                return simpleObject;
+            };
+
+            /**
+             * Publish the public methods.
+             */
+            return {
+                assert: assert,
+                convertToSimpleObject: convertToSimpleObject,
+                isNonEmptyString: isNonEmptyString,
+                isUndefinedOrNull: isUndefinedOrNull,
+                buildPropertyPath: buildPropertyPath
+            };
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function propertyValidationService() {
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @param object validators
+             * @param string propertyPath
+             * @param string collectionElementIdentifier
+             * @param string collectionName
+             * @param object configuration
+             * @return void
+             * @throws 1475661025
+             * @throws 1475661026
+             * @throws 1479238074
+             */
+            function addValidatorIdentifiersToFormElementProperty(formElement, validators, propertyPath, collectionElementIdentifier, collectionName, configuration) {
+                var formElementIdentifierPath, propertyPath, propertyValidationServiceRegisteredValidators;
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475661025);
+                utility().assert('array' === $.type(validators), 'Invalid parameter "validators"', 1475661026);
+                utility().assert('array' === $.type(validators), 'Invalid parameter "validators"', 1479238074);
+
+                formElementIdentifierPath = formElement.get('__identifierPath');
+                propertyPath = utility().buildPropertyPath(propertyPath, collectionElementIdentifier, collectionName, formElement);
+
+                propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
+                if (utility().isUndefinedOrNull(propertyValidationServiceRegisteredValidators[formElementIdentifierPath])) {
+                    propertyValidationServiceRegisteredValidators[formElementIdentifierPath] = {};
+                }
+                if (utility().isUndefinedOrNull(propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath])) {
+                    propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath] = {
+                        validators: [],
+                        configuration: configuration
+                    };
+                }
+                for (var i = 0, len = validators.length; i < len; ++i) {
+                    if (propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath]['validators'].indexOf(validators[i]) === -1) {
+                        propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath]['validators'].push(validators[i]);
+                    }
+                }
+                getApplicationStateStack().setCurrentState('propertyValidationServiceRegisteredValidators', propertyValidationServiceRegisteredValidators);
+            };
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @param string propertyPath
+             * @return void
+             * @throws 1475700618
+             * @throws 1475706896
+             */
+            function removeValidatorIdentifiersFromFormElementProperty(formElement, propertyPath) {
+                var formElementIdentifierPath, propertyValidationServiceRegisteredValidators, registeredValidators;
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475700618);
+                utility().assert(utility().isNonEmptyString(propertyPath), 'Invalid parameter "propertyPath"', 1475706896);
+
+                formElementIdentifierPath = formElement.get('__identifierPath');
+
+                registeredValidators = {};
+                propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
+                for (var registeredPropertyPath in propertyValidationServiceRegisteredValidators[formElementIdentifierPath]) {
+                    if (
+                        !propertyValidationServiceRegisteredValidators[formElementIdentifierPath].hasOwnProperty(registeredPropertyPath)
+                        || registeredPropertyPath.indexOf(propertyPath) > -1
+                    ) {
+                        continue;
+                    }
+                    registeredValidators[registeredPropertyPath] = propertyValidationServiceRegisteredValidators[formElementIdentifierPath][registeredPropertyPath];
+                }
+                propertyValidationServiceRegisteredValidators[formElementIdentifierPath] = registeredValidators;
+                getApplicationStateStack().setCurrentState('propertyValidationServiceRegisteredValidators', propertyValidationServiceRegisteredValidators);
+            };
+
+            /**
+             * @public
+             *
+             * @param string|object formElement
+             * @return void
+             * @throws 1475668189
+             */
+            function removeAllValidatorIdentifiersFromFormElement(formElement) {
+                var propertyValidationServiceRegisteredValidators, registeredValidators;
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475668189);
+
+                registeredValidators = {};
+                propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
+                for (var formElementIdentifierPath in propertyValidationServiceRegisteredValidators) {
+                    if (
+                        !propertyValidationServiceRegisteredValidators.hasOwnProperty(formElementIdentifierPath)
+                        || formElementIdentifierPath === formElement.get('__identifierPath')
+                        || formElementIdentifierPath.indexOf(formElement.get('__identifierPath') + '/') > -1
+                    ) {
+                        continue;
+                    }
+                    registeredValidators[formElementIdentifierPath] = propertyValidationServiceRegisteredValidators[formElementIdentifierPath];
+                }
+                getApplicationStateStack().setCurrentState('propertyValidationServiceRegisteredValidators', registeredValidators);
+            };
+
+            /**
+             * @public
+             *
+             * @param string validatorIdentifier
+             * @param function func
+             * @return void
+             * @throws 1475669143
+             * @throws 1475669144
+             * @throws 1475669145
+             */
+            function addValidator(validatorIdentifier, func) {
+                utility().assert(utility().isNonEmptyString(validatorIdentifier), 'Invalid parameter "validatorIdentifier"', 1475669143);
+                utility().assert('function' === $.type(func), 'Invalid parameter "func"', 1475669144);
+                utility().assert('function' !== $.type(_propertyValidationServiceValidators[validatorIdentifier]), 'The validator "' + validatorIdentifier + '" is already registered', 1475669145);
+
+                _propertyValidationServiceValidators[validatorIdentifier] = func;
+            };
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @param string propertyPath
+             * @param string errorMessage
+             * @return object
+             * @throws 1475676517
+             * @throws 1475676518
+             */
+            function validateFormElementProperty(formElement, propertyPath) {
+                var configuration, formElementIdentifierPath, propertyValidationServiceRegisteredValidators, validationResults;
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475676517);
+                utility().assert(utility().isNonEmptyString(propertyPath), 'Invalid parameter "propertyPath"', 1475676518);
+
+                formElementIdentifierPath = formElement.get('__identifierPath');
+
+                validationResults = [];
+                propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
+                configuration = {
+                    propertyValidatorsMode: 'AND'
+                };
+
+                if (
+                    !utility().isUndefinedOrNull(propertyValidationServiceRegisteredValidators[formElementIdentifierPath])
+                    && 'object' === $.type(propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath])
+                    && 'array' === $.type(propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath]['validators'])
+                ) {
+                    configuration = propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath]['configuration'];
+                    for (var i = 0, len = propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath]['validators'].length; i < len; ++i) {
+                        var validatorIdentifier, validationResult;
+
+                        validatorIdentifier = propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath]['validators'][i];
+                        if ('function' !== $.type(_propertyValidationServiceValidators[validatorIdentifier])) {
+                            continue;
+                        }
+                        validationResult = _propertyValidationServiceValidators[validatorIdentifier](formElement, propertyPath);
+
+                        if (utility().isNonEmptyString(validationResult)) {
+                            validationResults.push(validationResult);
+                        }
+                    }
+                }
+
+                if (
+                    validationResults.length > 0
+                    && configuration['propertyValidatorsMode'] === 'OR'
+                    && validationResults.length !== propertyValidationServiceRegisteredValidators[formElementIdentifierPath][propertyPath]['validators'].length
+                ) {
+                    return [];
+                }
+
+                return validationResults;
+            };
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @return object
+             * @throws 1475749668
+             */
+            function validateFormElement(formElement) {
+                var formElementIdentifierPath, propertyValidationServiceRegisteredValidators, validationResults;
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475749668);
+
+                formElementIdentifierPath = formElement.get('__identifierPath');
+
+                validationResults = [];
+                propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
+                if (!utility().isUndefinedOrNull(propertyValidationServiceRegisteredValidators[formElementIdentifierPath])) {
+                    for (var registeredPropertyPath in propertyValidationServiceRegisteredValidators[formElementIdentifierPath]) {
+                        var validationResult;
+                        if (!propertyValidationServiceRegisteredValidators[formElementIdentifierPath].hasOwnProperty(registeredPropertyPath)) {
+                            continue;
+                        }
+                        validationResult = {
+                            propertyPath: registeredPropertyPath,
+                            validationResults: validateFormElementProperty(formElement, registeredPropertyPath)
+                        };
+                        validationResults.push(validationResult);
+                    }
+                }
+                return validationResults;
+            };
+
+            /**
+             * @public
+             *
+             * @param array validationResults
+             * @return bool
+             * @throws 1478613477
+             */
+            function validationResultsHasErrors(validationResults) {
+                utility().assert('array' === $.type(validationResults), 'Invalid parameter "validationResults"', 1478613477);
+
+                for (var i = 0, len = validationResults.length; i < len; ++i) {
+                    for (var j = 0, len2 = validationResults[i]['validationResults'].length; j < len2; ++j) {
+                        if (
+                            validationResults[i]['validationResults'][j]['validationResults']
+                            && validationResults[i]['validationResults'][j]['validationResults'].length > 0
+                        ) {
+                            return true;
+                        }
+                    }
+                }
+                return false;
+            };
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @param boolean returnAfterFirstMatch
+             * @param object validationResults
+             * @return object
+             * @throws 1475749668
+             */
+            function validateFormElementRecursive(formElement, returnAfterFirstMatch, validationResults) {
+                var formElements, validationResult, validationResults;
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475756764);
+                returnAfterFirstMatch = !!returnAfterFirstMatch;
+
+                validationResults = validationResults || [];
+                validationResult = {
+                    formElementIdentifierPath: formElement.get('__identifierPath'),
+                    validationResults: validateFormElement(formElement)
+                };
+                validationResults.push(validationResult);
+
+                if (returnAfterFirstMatch && validationResultsHasErrors(validationResults)) {
+                    return validationResults;
+                }
+
+                formElements = formElement.get('renderables');
+                if ('array' === $.type(formElements)) {
+                    for (var i = 0, len = formElements.length; i < len; ++i) {
+                        validateFormElementRecursive(formElements[i], returnAfterFirstMatch, validationResults);
+                        if (returnAfterFirstMatch && validationResultsHasErrors(validationResults)) {
+                            return validationResults;
+                        }
+                    }
+                }
+
+                return validationResults;
+            }
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @return void
+             * @throws 1475707334
+             */
+            function addValidatorIdentifiersFromFormElementPropertyCollections(formElement) {
+                var formElementTypeDefinition;
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475707334);
+
+                formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
+
+                if (!utility().isUndefinedOrNull(formElementTypeDefinition['propertyCollections'])) {
+                    for (var collectionName in formElementTypeDefinition['propertyCollections']) {
+                        if (
+                            !formElementTypeDefinition['propertyCollections'].hasOwnProperty(collectionName)
+                            || 'array' !== $.type(formElementTypeDefinition['propertyCollections'][collectionName])
+                        ) {
+                            continue;
+                        }
+                        for (var i = 0, len1 = formElementTypeDefinition['propertyCollections'][collectionName].length; i < len1; ++i) {
+                            if (
+                                'array' !== $.type(formElementTypeDefinition['propertyCollections'][collectionName][i]['editors'])
+                                || repository().getIndexFromPropertyCollectionElementByIdentifier(formElementTypeDefinition['propertyCollections'][collectionName][i]['identifier'], collectionName, formElement) === -1
+                            ) {
+                                continue;
+                            }
+                            for (var j = 0, len2 = formElementTypeDefinition['propertyCollections'][collectionName][i]['editors'].length; j < len2; ++j) {
+                                var configuration = {};
+
+                                if ('array' !== $.type(formElementTypeDefinition['propertyCollections'][collectionName][i]['editors'][j]['propertyValidators'])) {
+                                    continue;
+                                }
+                                
+                                if (
+                                    !utility().isUndefinedOrNull(formElementTypeDefinition['propertyCollections'][collectionName][i]['editors'][j]['propertyValidatorsMode'])
+                                    && formElementTypeDefinition['propertyCollections'][collectionName][i]['editors'][j]['propertyValidatorsMode'] === 'OR'
+                                ) {
+                                    configuration['propertyValidatorsMode'] = 'OR';
+                                } else {
+                                    configuration['propertyValidatorsMode'] = 'AND';
+                                }
+                                addValidatorIdentifiersToFormElementProperty(
+                                    formElement,
+                                    formElementTypeDefinition['propertyCollections'][collectionName][i]['editors'][j]['propertyValidators'],
+                                    formElementTypeDefinition['propertyCollections'][collectionName][i]['editors'][j]['propertyPath'],
+                                    formElementTypeDefinition['propertyCollections'][collectionName][i]['identifier'],
+                                    collectionName,
+                                    configuration
+                                );
+                            }
+                        }
+                    }
+                }
+            };
+
+            /**
+             * Publish the public methods.
+             */
+            return {
+                addValidatorIdentifiersToFormElementProperty: addValidatorIdentifiersToFormElementProperty,
+                removeValidatorIdentifiersFromFormElementProperty: removeValidatorIdentifiersFromFormElementProperty,
+                removeAllValidatorIdentifiersFromFormElement: removeAllValidatorIdentifiersFromFormElement,
+                validateFormElementProperty: validateFormElementProperty,
+                validateFormElement: validateFormElement,
+                validateFormElementRecursive: validateFormElementRecursive,
+                validationResultsHasErrors: validationResultsHasErrors,
+                addValidator: addValidator,
+                addValidatorIdentifiersFromFormElementPropertyCollections: addValidatorIdentifiersFromFormElementPropertyCollections
+            };
+        };
+
+        /**
+         * @public
+         *
+         * @param string ajaxRequestIdentifier
+         * @return object|null
+         * @throws 1475358064
+         */
+        function getRunningAjaxRequest(ajaxRequestIdentifier) {
+            utility().assert(utility().isNonEmptyString(ajaxRequestIdentifier), 'Invalid parameter "ajaxRequestIdentifier"', 1475358064);
+            return _runningAjaxRequests[ajaxRequestIdentifier] || null;
+        };
+
+        /**
+         * @public
+         *
+         * Implements the "Publish/Subscribe Pattern"
+         *
+         * @return object
+         * @credits Addy Osmani https://addyosmani.com/resources/essentialjsdesignpatterns/book/#highlighter_634280
+         */
+        function publisherSubscriber() {
+
+            /**
+             * @public
+             *
+             * @param string topic
+             * @param mixed args
+             * @return void
+             * @throws 1475358066
+             */
+            function publish(topic, args) {
+                utility().assert(utility().isNonEmptyString(topic), 'Invalid parameter "topic"', 1475358066);
+                if (utility().isUndefinedOrNull(_publisherSubscriberTopics[topic])) {
+                    return;
+                }
+
+                for (var i = 0, len = _publisherSubscriberTopics[topic].length; i < len; ++i) {
+                    _publisherSubscriberTopics[topic][i].func(topic, args);
+                }
+            };
+
+            /**
+             * @public
+             *
+             * @param string topic
+             * @param function func
+             * @return string
+             * @throws 1475358067
+             */
+            function subscribe(topic, func) {
+                utility().assert(utility().isNonEmptyString(topic), 'Invalid parameter "topic"', 1475358067);
+                utility().assert('function' === $.type(func), 'Invalid parameter "func"', 1475411986);
+
+                if (utility().isUndefinedOrNull(_publisherSubscriberTopics[topic])) {
+                    _publisherSubscriberTopics[topic] = [];
+                }
+
+                var token = (++_publisherSubscriberUid).toString();
+                _publisherSubscriberTopics[topic].push({
+                    token: token,
+                    func: func
+                });
+                return token;
+            };
+
+            /**
+             * @public
+             *
+             * @param string token
+             * @return null|string
+             * @throws 1475358068
+             */
+            function unsubscribe(token) {
+                utility().assert(utility().isNonEmptyString(token), 'Invalid parameter "token"', 1475358068);
+
+                for (var key in _publisherSubscriberTopics) {
+                    if (!_publisherSubscriberTopics.hasOwnProperty(key)) {
+                        continue;
+                    }
+                    for (var i = 0, len = _publisherSubscriberTopics[key].length; i < len; ++i) {
+                        if (_publisherSubscriberTopics[key][i].token === token) {
+                            _publisherSubscriberTopics[key].splice(i, 1);
+                            return token;
+                        }
+                    }
+                }
+                return null;
+            };
+
+            /**
+             * Publish the public methods.
+             */
+            return {
+                publish: publish,
+                subscribe: subscribe,
+                unsubscribe: unsubscribe
+            };
+        };
+
+        /**
+         * @private
+         *
+         * @param object modelToExtend
+         * @param object modelExtension
+         * @param string pathPrefix
+         * @return void
+         * @throws 1474640022
+         * @throws 1475358069
+         * @throws 1475358070
+         * @publish core/formElement/somePropertyChanged
+         */
+        function extendModel(modelToExtend, modelExtension, pathPrefix, disablePublishersOnSet) {
+            utility().assert('object' === $.type(modelToExtend), 'Invalid parameter "modelToExtend"', 1475358069);
+            utility().assert('object' === $.type(modelExtension) || 'array' === $.type(modelExtension), 'Invalid parameter "modelExtension"', 1475358070);
+
+            disablePublishersOnSet = !!disablePublishersOnSet;
+            pathPrefix = pathPrefix || '';
+
+            if ($.isEmptyObject(modelExtension)) {
+                utility().assert('' !== pathPrefix, 'Empty path is not allowed', 1474640022);
+                modelToExtend.on(pathPrefix, 'core/formElement/somePropertyChanged');
+                modelToExtend.set(pathPrefix, modelExtension, disablePublishersOnSet);
+            } else {
+                for (var key in modelExtension) {
+                    if (!modelExtension.hasOwnProperty(key)) {
+                        continue;
+                    }
+                    var path = (pathPrefix === '') ? key : pathPrefix + '.' + key;
+
+                    modelToExtend.on(path, 'core/formElement/somePropertyChanged');
+
+                    if ('object' === $.type(modelExtension[key]) || 'array' === $.type(modelExtension[key])) {
+                        extendModel(modelToExtend, modelExtension[key], path, disablePublishersOnSet);
+                    } else {
+                        modelToExtend.set(path, modelExtension[key], disablePublishersOnSet);
+                    }
+                }
+            }
+        };
+
+        /**
+         * @private
+         *
+         * @param object modelExtension
+         * @return object
+         */
+        function createModel(modelExtension) {
+            var newModel;
+
+            modelExtension = modelExtension || {};
+
+            function M() {
+
+                /**
+                 * @private
+                 */
+                var _objectData = {};
+
+                /**
+                 * @private
+                 */
+                var _publisherTopics = {};
+
+                /**
+                 * @public
+                 *
+                 * @param string key
+                 * @return mixed|undefined
+                 * @throws 1475361755
+                 */
+                function get(key) {
+                    var firstPartOfPath, obj;
+                    utility().assert(utility().isNonEmptyString(key), 'Invalid parameter "key"', 1475361755);
+
+                    obj = _objectData;
+                    while (key.indexOf('.') > 0) {
+                        firstPartOfPath = key.slice(0, key.indexOf('.'));
+                        key = key.slice(firstPartOfPath.length + 1);
+                        if (!obj.hasOwnProperty(firstPartOfPath)) {
+                            return undefined;
+                        }
+                        obj = obj[firstPartOfPath];
+                    }
+
+                    return obj[key];
+                };
+
+                /**
+                 * @public
+                 *
+                 * @param string key
+                 * @param mixed value
+                 * @param bool disablePublishersOnSet
+                 * @return void
+                 * @throws 1475361756
+                 * @publish mixed
+                 */
+                function set(key, value, disablePublishersOnSet) {
+                    var obj, oldValue, path;
+                    utility().assert(utility().isNonEmptyString(key), 'Invalid parameter "key"', 1475361756);
+                    disablePublishersOnSet = !!disablePublishersOnSet;
+
+                    oldValue = get(key);
+                    obj = _objectData;
+                    path = key;
+
+                    while (path.indexOf('.') > 0) {
+                        var firstPartOfPath, nextPartOfPath;
+
+                        firstPartOfPath = path.slice(0, path.indexOf('.'));
+                        path = path.slice(firstPartOfPath.length + 1);
+                        if ($.isNumeric(firstPartOfPath)) {
+                            firstPartOfPath = parseInt(firstPartOfPath);
+                        }
+                        if ('undefined' === $.type(obj[firstPartOfPath])) {
+                            nextPartOfPath = path.slice(0, path.indexOf('.'));
+                            if ($.isNumeric(nextPartOfPath)) {
+                                obj[firstPartOfPath] = [];
+                            } else {
+                                obj[firstPartOfPath] = {};
+                            }
+                        }
+                        obj = obj[firstPartOfPath];
+                    }
+                    obj[path] = value;
+
+                    if (!utility().isUndefinedOrNull(_publisherTopics[key]) && !disablePublishersOnSet) {
+                        for (var i = 0, len = _publisherTopics[key].length; i < len; ++i) {
+                            publisherSubscriber().publish(_publisherTopics[key][i], [key, value, oldValue, _objectData['__identifierPath']]);
+                        }
+                    }
+                };
+
+                /**
+                 * @public
+                 *
+                 * @param string key
+                 * @param string topicName
+                 * @return void
+                 * @throws 1475361757
+                 * @throws 1475361758
+                 */
+                function on(key, topicName) {
+                    utility().assert(utility().isNonEmptyString(key), 'Invalid parameter "key"', 1475361757);
+                    utility().assert(utility().isNonEmptyString(topicName), 'Invalid parameter "topicName"', 1475361758);
+
+                    if ('array' !== $.type(_publisherTopics[key])) {
+                        _publisherTopics[key] = [];
+                    }
+                    if (_publisherTopics[key].indexOf(topicName) === -1) {
+                        _publisherTopics[key].push(topicName);
+                    }
+                };
+
+                /**
+                 * @public
+                 *
+                 * @param string key
+                 * @param string topicName
+                 * @return void
+                 * @throws 1475361759
+                 * @throws 1475361760
+                 */
+                function off(key, topicName) {
+                    utility().assert(utility().isNonEmptyString(key), 'Invalid parameter "key"', 1475361759);
+                    utility().assert(utility().isNonEmptyString(topicName), 'Invalid parameter "topicName"', 1475361760);
+
+                    if ('array' === $.type(_publisherTopics[key])) {
+                        _publisherTopics[key] = _publisherTopics[key].filter(function (topicName) {
+                            return topicName !== topicName;
+                        });
+                    }
+                };
+
+                /**
+                 * @public
+                 *
+                 * @return object (dereferenced)
+                 */
+                function getObjectData() {
+                    return $.extend(true, {}, _objectData);
+                };
+
+                /**
+                 * @public
+                 *
+                 * @return string
+                 */
+                function toString() {
+                    var childFormElements, objectData;
+
+                    objectData = getObjectData();
+                    childFormElements = objectData['renderables'] || null;
+                    delete objectData['renderables'];
+
+                    if (!utility().isUndefinedOrNull(objectData['__parentRenderable'])) {
+                        objectData['__parentRenderable'] = objectData['__parentRenderable'].getObjectData()['__identifierPath'] + ' (filtered)';
+                    }
+
+                    if (null !== childFormElements) {
+                        objectData['renderables'] = [];
+                        for (var i = 0, len = childFormElements.length; i < len; ++i) {
+                            var childFormElement = childFormElements[i];
+                            objectData['renderables'].push(JSON.parse(childFormElement.toString()));
+                        }
+                    }
+
+                    return JSON.stringify(objectData, null, 2);
+                };
+
+                /**
+                 * @public
+                 *
+                 * @return object
+                 */
+                function clone() {
+                    var childFormElements, newModel, newRenderables, objectData;
+
+                    objectData = getObjectData();
+                    childFormElements = objectData['renderables'] || null;
+                    delete objectData['renderables'];
+                    delete objectData['__parentRenderable'];
+                    objectData['renderables'] = (childFormElements) ? true : null,
+
+                    newModel = new M();
+                    extendModel(newModel, objectData, '', true);
+
+                    if (null !== childFormElements) {
+                        newRenderables = [];
+                        for (var i = 0, len = childFormElements.length; i < len; ++i) {
+                            var childFormElement = childFormElements[i];
+
+                            childFormElement = childFormElement.clone();
+                            childFormElement.set('__parentRenderable', newModel, true);
+                            newRenderables.push(childFormElement);
+                        }
+                        newModel.set('renderables', newRenderables, true);
+                    }
+
+                    return newModel;
+                };
+
+                /**
+                 * Publish the public methods.
+                 */
+                return {
+                    get: get,
+                    set: set,
+
+                    on: on,
+                    off: off,
+
+                    getObjectData: getObjectData,
+                    toString: toString,
+                    clone: clone
+                };
+            };
+
+            newModel = new M();
+            extendModel(newModel, modelExtension, '', true);
+
+            return newModel;
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function repository() {
+
+            /**
+             * @public
+             *
+             * @param object typeDefinitions
+             * @return void
+             * @throws 1475364394
+             */
+            function setFormEditorDefinitions(formEditorDefinitions) {
+                utility().assert('object' === $.type(formEditorDefinitions), 'Invalid parameter "formEditorDefinitions"', 1475364394);
+
+                for (var key1 in formEditorDefinitions) {
+                    if (!formEditorDefinitions.hasOwnProperty(key1) || 'object' !== $.type(formEditorDefinitions[key1])) {
+                        continue;
+                    }
+                    for (var key2 in formEditorDefinitions[key1]) {
+                        if (!formEditorDefinitions[key1].hasOwnProperty(key2)) {
+                            continue;
+                        }
+                        if ('object' !== $.type(formEditorDefinitions[key1][key2])) {
+                            formEditorDefinitions[key1][key2] = {};
+                        }
+                    }
+                }
+                _repositoryFormEditorDefinitions = formEditorDefinitions;
+            };
+
+            /**
+             * @public
+             *
+             * @param string typeName
+             * @param string subject
+             * @return object (dereferenced)
+             * @throws 1475364952
+             * @throws 1475364953
+             */
+            function getFormEditorDefinition(definitionName, subject) {
+                utility().assert(utility().isNonEmptyString(definitionName), 'Invalid parameter "definitionName"', 1475364952);
+                utility().assert(utility().isNonEmptyString(subject), 'Invalid parameter "subject"', 1475364953);
+                return $.extend(true, {}, _repositoryFormEditorDefinitions[definitionName][subject]);
+            };
+
+            /**
+             * @public
+             *
+             * @return object
+             */
+            function getRootFormElement() {
+                return getApplicationStateStack().getCurrentState('formDefinition');
+            };
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @param object referenceFormElement
+             * @param boolean registerPropertyValidators
+             * @param boolean disablePublishersOnSet
+             * @return object
+             * @throws 1475436224
+             * @throws 1475364956
+             */
+            function addFormElement(formElement, referenceFormElement, registerPropertyValidators, disablePublishersOnSet) {
+                var enclosingCompositeFormElement, identifier, formElementTypeDefinition, parentFormElementsArray, referenceFormElementElements, referenceFormElementTypeDefinition;
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475436224);
+                utility().assert('object' === $.type(referenceFormElement), 'Invalid parameter "referenceFormElement"', 1475364956);
+
+                if (utility().isUndefinedOrNull(disablePublishersOnSet)) {
+                    disablePublishersOnSet = true;
+                }
+                disablePublishersOnSet = !!disablePublishersOnSet;
+
+                registerPropertyValidators = !!registerPropertyValidators;
+                formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
+                referenceFormElementTypeDefinition = repository().getFormEditorDefinition('formElements', referenceFormElement.get('type'));
+
+                if (!formElementTypeDefinition['_isTopLevelFormElement'] && referenceFormElementTypeDefinition['_isCompositeFormElement']) {
+                    if ('array' !== $.type(referenceFormElement.get('renderables'))) {
+                        referenceFormElement.set('renderables', [], disablePublishersOnSet);
+                    }
+
+                    formElement.set('__parentRenderable', referenceFormElement, disablePublishersOnSet);
+                    formElement.set('__identifierPath', referenceFormElement.get('__identifierPath') + '/' + formElement.get('identifier'), disablePublishersOnSet);
+                    referenceFormElement.get('renderables').push(formElement);
+                } else {
+                    if (referenceFormElement.get('__identifierPath') === getApplicationStateStack().getCurrentState('formDefinition').get('__identifierPath')) {
+                        referenceFormElementElements = referenceFormElement.get('renderables');
+                        referenceFormElement = referenceFormElementElements[referenceFormElementElements.length - 1];
+                    } else if (formElementTypeDefinition['_isTopLevelFormElement'] && !referenceFormElementTypeDefinition['_isTopLevelFormElement']) {
+                        referenceFormElement = findEnclosingCompositeFormElementWhichIsOnTopLevel(referenceFormElement);
+                    } else if (formElementTypeDefinition['_isCompositeFormElement']) {
+                        enclosingCompositeFormElement = findEnclosingCompositeFormElementWhichIsNotOnTopLevel(referenceFormElement);
+                        if (enclosingCompositeFormElement) {
+                            referenceFormElement = enclosingCompositeFormElement;
+                        }
+                    }
+
+                    formElement.set('__parentRenderable', referenceFormElement.get('__parentRenderable'), disablePublishersOnSet);
+                    formElement.set('__identifierPath', referenceFormElement.get('__parentRenderable').get('__identifierPath') + '/' + formElement.get('identifier'), disablePublishersOnSet);
+                    parentFormElementsArray = referenceFormElement.get('__parentRenderable').get('renderables');
+                    parentFormElementsArray.splice(parentFormElementsArray.indexOf(referenceFormElement) + 1, 0, formElement);
+                }
+
+                if (registerPropertyValidators) {
+                    if ('array' === $.type(formElementTypeDefinition['editors'])) {
+                        for (var i = 0, len1 = formElementTypeDefinition['editors'].length; i < len1; ++i) {
+                            var configuration = {};
+
+                            if ('array' !== $.type(formElementTypeDefinition['editors'][i]['propertyValidators'])) {
+                                continue;
+                            }
+
+                            if (
+                                !utility().isUndefinedOrNull(formElementTypeDefinition['editors'][i]['propertyValidatorsMode'])
+                                && formElementTypeDefinition['editors'][i]['propertyValidatorsMode'] === 'OR'
+                            ) {
+                                configuration['propertyValidatorsMode'] = 'OR';
+                            } else {
+                                configuration['propertyValidatorsMode'] = 'AND';
+                            }
+
+                            propertyValidationService().addValidatorIdentifiersToFormElementProperty(
+                                formElement,
+                                formElementTypeDefinition['editors'][i]['propertyValidators'],
+                                formElementTypeDefinition['editors'][i]['propertyPath'],
+                                undefined,
+                                undefined,
+                                configuration
+                            );
+                        }
+                    }
+                }
+
+                return formElement;
+            };
+
+            /**
+             * @param object formElement
+             * @param boolean removeRegisteredPropertyValidators
+             * @param boolean disablePublishersOnSet
+             * @return void
+             * @throws 1472553024
+             * @throws 1475364957
+             */
+            function removeFormElement(formElement, removeRegisteredPropertyValidators, disablePublishersOnSet) {
+                var parentFormElementElements;
+
+                if (utility().isUndefinedOrNull(disablePublishersOnSet)) {
+                    disablePublishersOnSet = true;
+                }
+                disablePublishersOnSet = !!disablePublishersOnSet;
+                removeRegisteredPropertyValidators = !!removeRegisteredPropertyValidators;
+
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364957);
+                utility().assert('object' === $.type(formElement.get('__parentRenderable')), 'Removing the root element is not allowed', 1472553024);
+
+                parentFormElementElements = formElement.get('__parentRenderable').get('renderables');
+                parentFormElementElements.splice(parentFormElementElements.indexOf(formElement), 1);
+                formElement.get('__parentRenderable').set('renderables', parentFormElementElements, disablePublishersOnSet);
+
+                if (removeRegisteredPropertyValidators) {
+                    propertyValidationService().removeAllValidatorIdentifiersFromFormElement(formElement);
+                }
+            };
+
+            /**
+             * @param object formElementToMove
+             * @param string position
+             * @param object referenceFormElement
+             * @param boolean disablePublishersOnSet
+             * @return object
+             * @throws 1475364958
+             * @throws 1475364959
+             * @throws 1475364960
+             * @throws 1475364961
+             * @throws 1475364962
+             * @throws 1476993731
+             * @throws 1476993732
+             */
+            function moveFormElement(formElementToMove, position, referenceFormElement, disablePublishersOnSet) {
+                var formElementToMoveTypeDefinition, referenceFormElementParentElements, referenceFormElementElements, referenceFormElementIndex, referenceFormElementTypeDefinition, reSetIdentifierPath;
+                utility().assert('object' === $.type(formElementToMove), 'Invalid parameter "formElementToMove"', 1475364958);
+                utility().assert('after' === position || 'before' === position || 'inside' === position, 'Invalid position "' + position + '"', 1475364959);
+                utility().assert('object' === $.type(referenceFormElement), 'Invalid parameter "referenceFormElement"', 1475364960);
+
+                if (utility().isUndefinedOrNull(disablePublishersOnSet)) {
+                    disablePublishersOnSet = true;
+                }
+                disablePublishersOnSet = !!disablePublishersOnSet;
+
+                formElementToMoveTypeDefinition = repository().getFormEditorDefinition('formElements', formElementToMove.get('type'));
+                referenceFormElementTypeDefinition = repository().getFormEditorDefinition('formElements', referenceFormElement.get('type'));
+
+                removeFormElement(formElementToMove, false);
+                reSetIdentifierPath = function(formElement, pathPrefix) {
+                    var formElements, newIdentifierPath, oldIdentifierPath, propertyValidationServiceRegisteredValidators;
+                    utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364961);
+                    utility().assert(utility().isNonEmptyString(pathPrefix), 'Invalid parameter "pathPrefix"', 1475364962);
+
+                    oldIdentifierPath = formElement.get('__identifierPath');
+                    newIdentifierPath = pathPrefix + '/' + formElement.get('identifier');
+
+                    propertyValidationServiceRegisteredValidators = getApplicationStateStack().getCurrentState('propertyValidationServiceRegisteredValidators');
+                    if (!utility().isUndefinedOrNull(propertyValidationServiceRegisteredValidators[oldIdentifierPath])) {
+                        propertyValidationServiceRegisteredValidators[newIdentifierPath] = propertyValidationServiceRegisteredValidators[oldIdentifierPath];
+                        delete propertyValidationServiceRegisteredValidators[oldIdentifierPath];
+                    }
+                    getApplicationStateStack().setCurrentState('propertyValidationServiceRegisteredValidators', propertyValidationServiceRegisteredValidators);
+
+                    formElement.set('__identifierPath', newIdentifierPath, disablePublishersOnSet);
+                    formElements = formElement.get('renderables');
+                    if ('array' === $.type(formElements)) {
+                        for (var i = 0, len = formElements.length; i < len; ++i) {
+                            reSetIdentifierPath(formElements[i], formElement.get('__identifierPath'));
+                        }
+                    }
+                };
+
+                /**
+                 * This is true on:
+                 * * Drag a Element on a Page Element (tree)
+                 * * Drag a Element on a Section Element (tree)
+                 */
+                if (position === 'inside') {
+                    utility().assert(!formElementToMoveTypeDefinition['_isTopLevelFormElement'], 'This move is not allowed', 1476993731);
+                    utility().assert(referenceFormElementTypeDefinition['_isCompositeFormElement'], 'This move is not allowed', 1476993732);
+
+                    formElementToMove.set('__parentRenderable', referenceFormElement, disablePublishersOnSet);
+                    reSetIdentifierPath(formElementToMove, referenceFormElement.get('__identifierPath'));
+
+                    referenceFormElementElements = referenceFormElement.get('renderables');
+                    if (utility().isUndefinedOrNull(referenceFormElementElements)) {
+                        referenceFormElementElements = [];
+                    }
+                    referenceFormElementElements.splice(0, 0, formElementToMove);
+                    referenceFormElement.set('renderables', referenceFormElementElements, disablePublishersOnSet);
+                } else {
+                    /**
+                     * This is true on:
+                     * * Drag a Page before another Page (tree)
+                     * * Drag a Page after another Page (tree)
+                     */
+                    if (formElementToMoveTypeDefinition['_isTopLevelFormElement'] && referenceFormElementTypeDefinition['_isTopLevelFormElement']) {
+                        referenceFormElementParentElements = referenceFormElement.get('__parentRenderable').get('renderables');
+                        referenceFormElementIndex = referenceFormElementParentElements.indexOf(referenceFormElement);
+
+                        if (position === 'after') {
+                            referenceFormElementParentElements.splice(referenceFormElementIndex + 1, 0, formElementToMove);
+                        } else {
+                            referenceFormElementParentElements.splice(referenceFormElementIndex, 0, formElementToMove);
+                        }
+
+                        referenceFormElement.get('__parentRenderable').set('renderables', referenceFormElementParentElements, disablePublishersOnSet);
+                    } else {
+                        /**
+                         * This is true on:
+                         * * Drag a Element before another Element within the same level (tree)
+                         * * Drag a Element after another Element within the same level (tree)
+                         * * Drag a Element before another Element (stage)
+                         * * Drag a Element after another Element (stage)
+                         */
+                        if (formElementToMove.get('__parentRenderable').get('identifier') === referenceFormElement.get('__parentRenderable').get('identifier')) {
+                            referenceFormElementParentElements = referenceFormElement.get('__parentRenderable').get('renderables');
+                            referenceFormElementIndex = referenceFormElementParentElements.indexOf(referenceFormElement);
+                        } else {
+                            /**
+                             * This is true on:
+                             * * Drag a Element before an Element on another page (tree)
+                             * * Drag a Element after an Element on another page (tree)
+                             */
+                            formElementToMove.set('__parentRenderable', referenceFormElement.get('__parentRenderable'), disablePublishersOnSet);
+                            reSetIdentifierPath(formElementToMove, referenceFormElement.get('__parentRenderable').get('__identifierPath'));
+
+                            referenceFormElementParentElements = referenceFormElement.get('__parentRenderable').get('renderables');
+                            referenceFormElementIndex = referenceFormElementParentElements.indexOf(referenceFormElement);
+                        }
+
+                        if (position === 'after') {
+                            referenceFormElementParentElements.splice(referenceFormElementIndex + 1, 0, formElementToMove);
+                        } else {
+                            referenceFormElementParentElements.splice(referenceFormElementIndex, 0, formElementToMove);
+                        }
+
+                        referenceFormElement.get('__parentRenderable').set('renderables', referenceFormElementParentElements, disablePublishersOnSet);
+                    }
+                }
+
+                return formElementToMove;
+            };
+
+            /**
+             * @param object formElement
+             * @return int
+             * @throws 1475364963
+             */
+            function getIndexForEnclosingCompositeFormElementWhichIsOnTopLevelForFormElement(formElement) {
+                var enclosingCompositeFormElementWhichIsOnTopLevel, formElementTypeDefinition;
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364963);
+
+                formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
+
+                if (formElementTypeDefinition['_isTopLevelFormElement'] && formElementTypeDefinition['_isCompositeFormElement']) {
+                    enclosingCompositeFormElementWhichIsOnTopLevel = formElement;
+                } else if (formElement.get('__identifierPath') === getApplicationStateStack().getCurrentState('formDefinition').get('__identifierPath')) {
+                    enclosingCompositeFormElementWhichIsOnTopLevel = getApplicationStateStack().getCurrentState('formDefinition').get('renderables')[0];
+                } else {
+                    enclosingCompositeFormElementWhichIsOnTopLevel = findEnclosingCompositeFormElementWhichIsOnTopLevel(formElement);
+                }
+                return enclosingCompositeFormElementWhichIsOnTopLevel.get('__parentRenderable').get('renderables').indexOf(enclosingCompositeFormElementWhichIsOnTopLevel);
+            };
+
+            /**
+             * @param object formElement
+             * @return object
+             * @throws 1472556223
+             * @throws 1475364964
+             */
+            function findEnclosingCompositeFormElementWhichIsOnTopLevel(formElement) {
+                var formElementTypeDefinition;
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364964);
+                utility().assert('object' === $.type(formElement.get('__parentRenderable')), 'The root element is never encloused by anything', 1472556223);
+
+                formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
+                while (!formElementTypeDefinition['_isTopLevelFormElement']) {
+                    formElement = formElement.get('__parentRenderable');
+                    formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
+                }
+
+                return formElement;
+            };
+
+            /**
+             * @param object formElement
+             * @return object|null
+             * @throws 1475364965
+             */
+            function findEnclosingCompositeFormElementWhichIsNotOnTopLevel(formElement) {
+                var formElementTypeDefinition;
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475364965);
+
+                formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
+                while (!formElementTypeDefinition['_isCompositeFormElement']) {
+                    if (formElementTypeDefinition['_isTopLevelFormElement']) {
+                        return null;
+                    }
+                    formElement = formElement.get('__parentRenderable');
+                    formElementTypeDefinition = repository().getFormEditorDefinition('formElements', formElement.get('type'));
+                }
+                if (formElementTypeDefinition['_isTopLevelFormElement']) {
+                    return null;
+                }
+                return formElement;
+            };
+
+            /**
+             * @param string identifier
+             * @returl bool
+             * @throws 1475364966
+             */
+            function isFormElementIdentifierUsed(identifier) {
+                var checkIdentifier, identifierFound;
+                utility().assert(utility().isNonEmptyString(identifier), 'Invalid parameter "identifier"', 1475364966);
+
+                checkIdentifier = function(formElement) {
+                    var formElements;
+
+                    if (formElement.get('identifier') === identifier) {
+                        identifierFound = true;
+                    }
+
+                    if (!identifierFound) {
+                        formElements = formElement.get('renderables');
+                        if ('array' === $.type(formElements)) {
+                            for (var i = 0, len = formElements.length; i < len; ++i) {
+                                checkIdentifier(formElements[i]);
+                                if (identifierFound) {
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+
+                checkIdentifier(getApplicationStateStack().getCurrentState('formDefinition'));
+                return identifierFound;
+            };
+
+            /**
+             * @param string formElementType
+             * @return string
+             * @throws 1475373676
+             */
+            function getNextFreeFormElementIdentifier(formElementType) {
+                var i, prefix;
+                utility().assert(utility().isNonEmptyString(formElementType), 'Invalid parameter "formElementType"', 1475373676);
+
+                prefix = formElementType.toLowerCase().replace(/[^a-z0-9]/g, '-') + '-';
+                i = 1;
+                while (isFormElementIdentifierUsed(prefix + i)) {
+                    i++;
+                }
+                return prefix + i;
+            };
+
+            /**
+             * @param string identifierPath
+             * @return object
+             * @throws 1472424333
+             * @throws 1472424334
+             * @throws 1472424330
+             * @throws 1475373677
+             */
+            function findFormElementByIdentifierPath(identifierPath) {
+                var obj, pathParts, pathPartsLength, formElement, formElements;
+
+                utility().assert(utility().isNonEmptyString(identifierPath), 'Invalid parameter "identifierPath"', 1475373677);
+
+                formElement = getApplicationStateStack().getCurrentState('formDefinition');
+                pathParts = identifierPath.split('/');
+                pathPartsLength = pathParts.length;
+
+                for (var i = 0; i < pathPartsLength; ++i) {
+                    var key = pathParts[i];
+                    if (i === 0 || i === pathPartsLength) {
+                        utility().assert(key === formElement.get('identifier'), '"' + key + '" does not exist in path "' + identifierPath + '"', 1472424333);
+                        continue;
+                    }
+
+                    formElements = formElement.get('renderables');
+                    if ('array' === $.type(formElements)) {
+                        obj = null;
+                        for (var j = 0, len = formElements.length; j < len; ++j) {
+                            if (key === formElements[j].get('identifier')) {
+                                obj = formElements[j];
+                                break;
+                            }
+                        }
+
+                        utility().assert('null' !== $.type(obj), 'Could not find form element "' + key + '" in path "' + identifierPath + '"', 1472424334);
+                        formElement = obj;
+                    } else {
+                        utility().assert(false, 'No form elements found', 1472424330);
+                    }
+                }
+                return formElement;
+            };
+
+            /**
+             * @param string|object formElement
+             * @return object
+             */
+            function findFormElement(formElement) {
+                if ('object' === $.type(formElement)) {
+                    formElement = formElement.get('__identifierPath');
+                }
+                return findFormElementByIdentifierPath(formElement);
+            };
+
+            /**
+             * @public
+             *
+             * @param string collectionElementIdentifier
+             * @param object collection
+             * @return undefined|object
+             * @throws 1475375281
+             * @throws 1475375282
+             */
+            function findCollectionElementByIdentifierPath(collectionElementIdentifier, collection) {
+                utility().assert(utility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475375281);
+                utility().assert('array' === $.type(collection), 'Invalid parameter "collection"', 1475375282);
+
+                for (var i = 0, len = collection.length; i < len; ++i) {
+                    if (collection[i]['identifier'] === collectionElementIdentifier) {
+                        return collection[i];
+                    }
+                }
+
+                return undefined;
+            };
+
+            /**
+             * @public
+             *
+             * @param string collectionElementIdentifier
+             * @param string collectionName
+             * @param object formElement
+             * @return int
+             * @throws 1475375283
+             * @throws 1475375284
+             * @throws 1475375285
+             */
+            function getIndexFromPropertyCollectionElementByIdentifier(collectionElementIdentifier, collectionName, formElement) {
+                var collection;
+                utility().assert(utility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475375283);
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475375284);
+                utility().assert(utility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475375285);
+
+                collection = formElement.get(collectionName);
+                if ('array' === $.type(collection)) {
+                    for (var i = 0, len = collection.length; i < len; ++i) {
+                        if (collection[i]['identifier'] === collectionElementIdentifier) {
+                            return i;
+                        }
+                    }
+                }
+                return -1;
+            };
+
+            /**
+             * @public
+             *
+             * @param object collectionElementToAdd
+             * @param string collectionName
+             * @param object formElement
+             * @param string referenceCollectionElementIdentifier
+             * @param boolean disablePublishersOnSet
+             * @return object
+             * @throws 1475375686
+             * @throws 1475375687
+             * @throws 1475375688
+             * @throws 1477413154
+             */
+            function addPropertyCollectionElement(collectionElementToAdd, collectionName, formElement, referenceCollectionElementIdentifier, disablePublishersOnSet) {
+                var collection, formElementTypeDefinition, newCollection, newCollectionElementIndex;
+                utility().assert('object' === $.type(collectionElementToAdd), 'Invalid parameter "collectionElementToAdd"', 1475375686);
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475375687);
+                utility().assert(utility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475375688);
+
+                if (utility().isUndefinedOrNull(disablePublishersOnSet)) {
+                    disablePublishersOnSet = true;
+                }
+                disablePublishersOnSet = !!disablePublishersOnSet;
+
+                collection = formElement.get(collectionName);
+                if ('array' !== $.type(collection)) {
+                    extendModel(formElement, [], collectionName, true);
+                    collection = formElement.get(collectionName);
+                }
+
+                if (utility().isUndefinedOrNull(referenceCollectionElementIdentifier)) {
+                    newCollectionElementIndex = 0;
+                } else {
+                    newCollectionElementIndex = getIndexFromPropertyCollectionElementByIdentifier(referenceCollectionElementIdentifier, collectionName, formElement) + 1;
+                    utility().assert(-1 < newCollectionElementIndex, 'Could not find collection element ' + referenceCollectionElementIdentifier + ' within collection ' + collectionName, 1477413154);
+                }
+
+                collection.splice(newCollectionElementIndex, 0, collectionElementToAdd);
+                formElement.set(collectionName, collection, true);
+
+                propertyValidationService().removeValidatorIdentifiersFromFormElementProperty(formElement, collectionName);
+
+                for (var i = 0, len = collection.length; i < len; ++i) {
+                    extendModel(formElement, collection[i], collectionName + '.' + i, true);
+                }
+
+                formElement.set(collectionName, collection, true);
+                propertyValidationService().addValidatorIdentifiersFromFormElementPropertyCollections(formElement);
+                formElement.set(collectionName, collection, disablePublishersOnSet);
+
+                return formElement;
+            };
+
+            /**
+             * @public
+             *
+             * @param object formElement
+             * @param string collectionElementIdentifier
+             * @param string collectionName
+             * @param boolean disablePublishersOnSet
+             * @return void
+             * @throws 1475375689
+             * @throws 1475375690
+             * @throws 1475375691
+             * @throws 1475375692
+             */
+            function removePropertyCollectionElementByIdentifier(formElement, collectionElementIdentifier, collectionName, disablePublishersOnSet) {
+                var collection, collectionElementIndex;
+                utility().assert(utility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475375689);
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1475375690);
+                utility().assert(utility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475375691);
+
+                collection = formElement.get(collectionName);
+                utility().assert('array' === $.type(collection), 'The collection "' + collectionName + '" does not exist', 1475375692);
+
+                if (utility().isUndefinedOrNull(disablePublishersOnSet)) {
+                    disablePublishersOnSet = true;
+                }
+                disablePublishersOnSet = !!disablePublishersOnSet;
+
+                propertyValidationService().removeValidatorIdentifiersFromFormElementProperty(formElement, collectionName);
+                collectionElementIndex = getIndexFromPropertyCollectionElementByIdentifier(collectionElementIdentifier, collectionName, formElement);
+                collection.splice(collectionElementIndex, 1);
+                formElement.set(collectionName, collection, disablePublishersOnSet);
+                propertyValidationService().addValidatorIdentifiersFromFormElementPropertyCollections(formElement);
+            };
+
+            /**
+             * @param string collectionElementToMoveIdentifier
+             * @param string position
+             * @param string referenceCollectionElementIdentifier
+             * @param string position
+             * @param object formElement
+             * @param boolean disablePublishersOnSet
+             * @return void
+             * @throws 1477404484
+             * @throws 1477404485
+             * @throws 1477404486
+             * @throws 1477404488
+             * @throws 1477404489
+             * @throws 1477404490
+             */
+            function movePropertyCollectionElement(collectionElementToMoveIdentifier, position, referenceCollectionElementIdentifier, collectionName, formElement, disablePublishersOnSet) {
+                var collection, collectionElementToMove, referenceCollectionElement, referenceCollectionElementIndex;
+
+                utility().assert('after' === position || 'before' === position, 'Invalid position "' + position + '"', 1477404485);
+                utility().assert('string' === $.type(referenceCollectionElementIdentifier), 'Invalid parameter "referenceCollectionElementIdentifier"', 1477404486);
+                utility().assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1477404488);
+
+                collection = formElement.get(collectionName);
+                utility().assert('array' === $.type(collection), 'The collection "' + collectionName + '" does not exist', 1477404490);
+
+                collectionElementToMove = findCollectionElementByIdentifierPath(collectionElementToMoveIdentifier, collection);
+                utility().assert('object' === $.type(collectionElementToMove), 'Invalid parameter "collectionElementToMove"', 1477404484);
+
+                removePropertyCollectionElementByIdentifier(formElement, collectionElementToMoveIdentifier, collectionName);
+
+                referenceCollectionElementIndex = getIndexFromPropertyCollectionElementByIdentifier(referenceCollectionElementIdentifier, collectionName, formElement);
+                utility().assert(-1 < referenceCollectionElementIndex, 'Could not find collection element ' + referenceCollectionElementIdentifier + ' within collection ' + collectionName, 1477404489);
+
+                if ('before' === position) {
+                    referenceCollectionElement = collection[referenceCollectionElementIndex - 1];
+                    if (utility().isUndefinedOrNull(referenceCollectionElement)) {
+                        referenceCollectionElementIdentifier = undefined;
+                    } else {
+                        referenceCollectionElementIdentifier = referenceCollectionElement['identifier'];
+                    }
+                }
+
+                addPropertyCollectionElement(collectionElementToMove, collectionName, formElement, referenceCollectionElementIdentifier, disablePublishersOnSet)
+            };
+
+            /**
+             * Publish the public methods.
+             */
+            return {
+                getRootFormElement: getRootFormElement,
+
+                getFormEditorDefinition: getFormEditorDefinition,
+                setFormEditorDefinitions: setFormEditorDefinitions,
+
+                findFormElement: findFormElement,
+                findFormElementByIdentifierPath: findFormElementByIdentifierPath,
+                findEnclosingCompositeFormElementWhichIsNotOnTopLevel: findEnclosingCompositeFormElementWhichIsNotOnTopLevel,
+                findEnclosingCompositeFormElementWhichIsOnTopLevel: findEnclosingCompositeFormElementWhichIsOnTopLevel,
+                getIndexForEnclosingCompositeFormElementWhichIsOnTopLevelForFormElement: getIndexForEnclosingCompositeFormElementWhichIsOnTopLevelForFormElement,
+
+                getNextFreeFormElementIdentifier: getNextFreeFormElementIdentifier,
+                isFormElementIdentifierUsed: isFormElementIdentifierUsed,
+
+                addFormElement: addFormElement,
+                moveFormElement: moveFormElement,
+                removeFormElement: removeFormElement,
+
+                findCollectionElementByIdentifierPath: findCollectionElementByIdentifierPath,
+                getIndexFromPropertyCollectionElementByIdentifier: getIndexFromPropertyCollectionElementByIdentifier,
+                addPropertyCollectionElement: addPropertyCollectionElement,
+                removePropertyCollectionElementByIdentifier: removePropertyCollectionElementByIdentifier,
+                movePropertyCollectionElement: movePropertyCollectionElement
+            };
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function factory() {
+
+            /**
+             * @public
+             *
+             * @param object configuration
+             * @param string identifierPathPrefix
+             * @param object parentFormElement
+             * @param boolean registerPropertyValidators
+             * @param boolean disablePublishersOnSet
+             * @return object
+             * @throws 1475375693
+             * @throws 1475436040
+             * @throws 1475604050
+             */
+            function createFormElement(configuration, identifierPathPrefix, parentFormElement, registerPropertyValidators, disablePublishersOnSet) {
+                var currentChildFormElements, collections, formElementTypeDefinition, identifierPath, rawChildFormElements, formElement;
+                utility().assert('object' === $.type(configuration), 'Invalid parameter "configuration"', 1475375693);
+                utility().assert(utility().isNonEmptyString(configuration['identifier']), '"identifier" must not be empty', 1475436040);
+                utility().assert(utility().isNonEmptyString(configuration['type']), '"type" must not be empty', 1475604050);
+
+                registerPropertyValidators = !!registerPropertyValidators;
+                if (utility().isUndefinedOrNull(disablePublishersOnSet)) {
+                    disablePublishersOnSet = true;
+                }
+                disablePublishersOnSet = !!disablePublishersOnSet;
+
+                formElementTypeDefinition = repository().getFormEditorDefinition('formElements', configuration['type']);
+                rawChildFormElements = configuration['renderables'];
+                delete configuration['renderables'];
+
+                collections = {};
+                for (var collectionName in configuration) {
+                    if (!configuration.hasOwnProperty(collectionName)) {
+                        continue;
+                    }
+                    if (utility().isUndefinedOrNull(_repositoryFormEditorDefinitions[collectionName])) {
+                        continue;
+                    }
+                    collections[collectionName] = configuration[collectionName];
+                    delete configuration[collectionName];
+                }
+
+                identifierPathPrefix = identifierPathPrefix || '';
+                identifierPath = (identifierPathPrefix === '') ? configuration['identifier'] : identifierPathPrefix + '/' + configuration['identifier'];
+
+                configuration = $.extend(
+                    formElementTypeDefinition['predefinedDefaults'] || {},
+                    configuration,
+                    {
+                        renderables: (rawChildFormElements) ? true : null,
+                        __parentRenderable: null,
+                        __identifierPath: identifierPath
+                    }
+                );
+
+                formElement = createModel(configuration);
+                formElement.set('__parentRenderable', parentFormElement || null, disablePublishersOnSet);
+
+                for (var collectionName in collections) {
+                    if (!collections.hasOwnProperty(collectionName)) {
+                        continue;
+                    }
+
+                    for (var i in collections[collectionName]) {
+                        var previousCreatePropertyCollectionElementIdentifier, propertyCollectionElement;
+                        if (!collections[collectionName].hasOwnProperty(i)) {
+                            continue;
+                        }
+                        propertyCollectionElement = createPropertyCollectionElement(
+                            collections[collectionName][i]['identifier'],
+                            collections[collectionName][i],
+                            collectionName
+                        );
+                        if (i > 0) {
+                            previousCreatePropertyCollectionElementIdentifier = collections[collectionName][i - 1]['identifier']
+                        }
+                        repository().addPropertyCollectionElement(propertyCollectionElement, collectionName, formElement, previousCreatePropertyCollectionElementIdentifier, true);
+                    }
+                }
+
+                if (registerPropertyValidators) {
+                    if ('array' === $.type(formElementTypeDefinition['editors'])) {
+                        for (var i = 0, len1 = formElementTypeDefinition['editors'].length; i < len1; ++i) {
+                            var configuration = {};
+
+                            if ('array' !== $.type(formElementTypeDefinition['editors'][i]['propertyValidators'])) {
+                                continue;
+                            }
+
+                            if (
+                                !utility().isUndefinedOrNull(formElementTypeDefinition['editors'][i]['propertyValidatorsMode'])
+                                && formElementTypeDefinition['editors'][i]['propertyValidatorsMode'] === 'OR'
+                            ) {
+                                configuration['propertyValidatorsMode'] = 'OR';
+                            } else {
+                                configuration['propertyValidatorsMode'] = 'AND';
+                            }
+
+                            propertyValidationService().addValidatorIdentifiersToFormElementProperty(
+                                formElement,
+                                formElementTypeDefinition['editors'][i]['propertyValidators'],
+                                formElementTypeDefinition['editors'][i]['propertyPath'],
+                                undefined,
+                                undefined,
+                                configuration
+                            );
+                        }
+                    }
+                }
+
+                if ('array' === $.type(rawChildFormElements)) {
+                    currentChildFormElements = [];
+                    for (var i = 0, len = rawChildFormElements.length; i < len; ++i) {
+                        currentChildFormElements.push(createFormElement(rawChildFormElements[i], identifierPath, formElement, registerPropertyValidators, disablePublishersOnSet));
+                    }
+                    formElement.set('renderables', currentChildFormElements, disablePublishersOnSet);
+                }
+                return formElement;
+            };
+
+            /**
+             * @public
+             *
+             * @param string collectionElementIdentifier
+             * @param object collectionElementConfiguration
+             * @param string collectionName
+             * @return object
+             * @throws 1475377160
+             * @throws 1475377161
+             * @throws 1475377162
+             */
+            function createPropertyCollectionElement(collectionElementIdentifier, collectionElementConfiguration, collectionName) {
+                var collectionDefinition, collectionElementPresets;
+                utility().assert(utility().isNonEmptyString(collectionElementIdentifier), 'Invalid parameter "collectionElementIdentifier"', 1475377160);
+                utility().assert('object' === $.type(collectionElementConfiguration), 'Invalid parameter "collectionElementConfiguration"', 1475377161);
+                utility().assert(utility().isNonEmptyString(collectionName), 'Invalid parameter "collectionName"', 1475377162);
+
+                collectionElementConfiguration['identifier'] = collectionElementIdentifier;
+                collectionDefinition = repository().getFormEditorDefinition(collectionName, collectionElementIdentifier);
+                if (collectionDefinition['predefinedDefaults']) {
+                    collectionElementPresets = collectionDefinition['predefinedDefaults'];
+                } else {
+                    collectionElementPresets = {};
+                }
+
+                return $.extend(collectionElementPresets, collectionElementConfiguration);
+            };
+
+            /**
+             * Publish the public methods.
+             */
+            return {
+                createFormElement: createFormElement,
+                createPropertyCollectionElement: createPropertyCollectionElement
+            };
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function dataBackend() {
+
+            /**
+             * @public
+             *
+             * @param object endpoints
+             * @return void
+             * @throws 1475377488
+             */
+            function setEndpoints(endpoints) {
+                utility().assert('object' === $.type(endpoints), 'Invalid parameter "endpoints"', 1475377488);
+                _dataBackendEndpoints = endpoints;
+            };
+
+            /**
+             * @public
+             *
+             * @param string prototypeName
+             * @return void
+             * @throws 1475377489
+             */
+            function setPrototypeName(prototypeName) {
+                utility().assert(utility().isNonEmptyString(prototypeName), 'Invalid parameter "prototypeName"', 1475928095);
+                _dataBackendPrototypeName = prototypeName;
+            };
+
+            /**
+             * @public
+             *
+             * @param string persistenceIdentifier
+             * @return void
+             * @throws 1475377489
+             */
+            function setPersistenceIdentifier(persistenceIdentifier) {
+                utility().assert(utility().isNonEmptyString(persistenceIdentifier), 'Invalid parameter "persistenceIdentifier"', 1475377489);
+                _dataBackendPersistenceIdentifier = persistenceIdentifier;
+            };
+
+            /**
+             * @public
+             *
+             * @return void
+             * @publish core/ajax/saveFormDefinition/success
+             * @publish core/ajax/error
+             * @throws 1475520918
+             */
+            function saveFormDefinition() {
+                utility().assert(utility().isNonEmptyString(_dataBackendEndpoints['saveForm']), 'The endpoint "saveForm" is not configured', 1475520918);
+
+                if (_runningAjaxRequests['saveForm']) {
+                    _runningAjaxRequests['saveForm'].abort();
+                }
+
+                _runningAjaxRequests['saveForm'] = $.post(_dataBackendEndpoints['saveForm'], {
+                    tx_form_web_formformbuilder: {
+                        formPersistenceIdentifier: _dataBackendPersistenceIdentifier,
+                        formDefinition: utility().convertToSimpleObject(getApplicationStateStack().getCurrentState('formDefinition'))
+                    }
+                }, function(data, textStatus, jqXHR) {
+                    if (_runningAjaxRequests['saveForm'] !== jqXHR) {
+                        return;
+                    }
+                    _runningAjaxRequests['saveForm'] = null;
+                    publisherSubscriber().publish('core/ajax/saveFormDefinition/success', [data]);
+                }).fail(function(jqXHR, textStatus, errorThrown) {
+                    publisherSubscriber().publish('core/ajax/error', [jqXHR, textStatus, errorThrown]);
+                });
+            };
+
+            /**
+             * @public
+             *
+             * @param int pageIndex
+             * @return void
+             * @publish core/ajax/renderFormDefinitionPage/success
+             * @publish core/ajax/error
+             * @throws 1473447677
+             * @throws 1475377781
+             * @throws 1475377782
+             */
+            function renderFormDefinitionPage(pageIndex) {
+                utility().assert($.isNumeric(pageIndex), 'Invalid parameter "pageIndex"', 1475377781);
+                utility().assert(utility().isNonEmptyString(_dataBackendEndpoints['formPageRenderer']), 'The endpoint "formPageRenderer" is not configured', 1473447677);
+
+                if (_runningAjaxRequests['renderFormDefinitionPage']) {
+                    _runningAjaxRequests['renderFormDefinitionPage'].abort();
+                }
+
+                _runningAjaxRequests['renderFormDefinitionPage'] = $.post(_dataBackendEndpoints['formPageRenderer'], {
+                    tx_form_web_formformbuilder: {
+                        formDefinition: utility().convertToSimpleObject(getApplicationStateStack().getCurrentState('formDefinition')),
+                        pageIndex: pageIndex,
+                        prototypeName: _dataBackendPrototypeName
+                    }
+                }, function(data, textStatus, jqXHR) {
+                    if (_runningAjaxRequests['renderFormDefinitionPage'] !== jqXHR) {
+                        return;
+                    }
+                    _runningAjaxRequests['renderFormDefinitionPage'] = null;
+                    publisherSubscriber().publish('core/ajax/renderFormDefinitionPage/success', [data, pageIndex]);
+                }).fail(function(jqXHR, textStatus, errorThrown) {
+                    publisherSubscriber().publish('core/ajax/error', [jqXHR, textStatus, errorThrown]);
+                });
+            };
+
+            /**
+             * Publish the public methods.
+             */
+            return {
+                renderFormDefinitionPage: renderFormDefinitionPage,
+                saveFormDefinition: saveFormDefinition,
+                setEndpoints: setEndpoints,
+                setPersistenceIdentifier: setPersistenceIdentifier,
+                setPrototypeName: setPrototypeName
+            };
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function getApplicationStateStack() {
+
+            /**
+             * @public
+             *
+             * @param object applicationState
+             * @param bool disablePublishersOnSet
+             * @return void
+             * @publish core/applicationState/add
+             * @throws 1477847415
+             */
+            function add(applicationState, disablePublishersOnSet) {
+                utility().assert('object' === $.type(applicationState), 'Invalid parameter "applicationState"', 1477847415);
+                disablePublishersOnSet = !!disablePublishersOnSet;
+
+                $.extend(applicationState, {
+                    propertyValidationServiceRegisteredValidators: $.extend(true, {}, getCurrentState('propertyValidationServiceRegisteredValidators'))
+                });
+
+                _applicationStateStack.splice(0, 0, applicationState);
+                if (_applicationStateStack.length > _applicationStateStackSize) {
+                    _applicationStateStack.splice(_applicationStateStackSize - 1, (_applicationStateStack.length - _applicationStateStackSize));
+                }
+
+                if (!disablePublishersOnSet) {
+                    publisherSubscriber().publish('core/applicationState/add', [applicationState, getCurrentStackPointer(), getCurrentStackSize()]);
+                }
+            };
+
+            /**
+             * @public
+             *
+             * @param applicationState
+             * @param bool disablePublishersOnSet
+             * @return void
+             * @publish core/applicationState/add
+             * @throws 1477872641
+             */
+            function addAndReset(applicationState, disablePublishersOnSet) {
+                utility().assert('object' === $.type(applicationState), 'Invalid parameter "applicationState"', 1477872641);
+
+                if (_applicationStateStackPointer > 0) {
+                    _applicationStateStack.splice(0, _applicationStateStackPointer);
+                }
+
+                _applicationStateStackPointer = 0;
+                add(applicationState, true);
+
+                if (!disablePublishersOnSet) {
+                    publisherSubscriber().publish('core/applicationState/add', [getCurrentState(), getCurrentStackPointer(), getCurrentStackSize()]);
+                }
+            };
+
+            /**
+             * @public
+             *
+             * @param string
+             * @return object
+             * @throws 1477932754
+             */
+            function getCurrentState(type) {
+                if (!utility().isUndefinedOrNull(type)) {
+                    utility().assert(
+                        'formDefinition' === type
+                        || 'currentlySelectedPageIndex' === type
+                        || 'currentlySelectedFormElementIdentifierPath' === type
+                        || 'propertyValidationServiceRegisteredValidators' === type,
+
+                        'Invalid parameter "type"', 1477932754
+                    );
+
+                    if ('undefined' === $.type(_applicationStateStack[_applicationStateStackPointer])) {
+                        return undefined;
+                    }
+                    return _applicationStateStack[_applicationStateStackPointer][type];
+                }
+                return _applicationStateStack[_applicationStateStackPointer];
+            };
+
+            /**
+             * @public
+             *
+             * @param string
+             * @param mixed
+             * @return void
+             * @throws 1477934111
+             */
+            function setCurrentState(type, value) {
+                utility().assert(
+                    'formDefinition' === type
+                    || 'currentlySelectedPageIndex' === type
+                    || 'currentlySelectedFormElementIdentifierPath' === type
+                    || 'propertyValidationServiceRegisteredValidators' === type,
+
+                    'Invalid parameter "type"', 1477934111
+                );
+                _applicationStateStack[_applicationStateStackPointer][type] = value;
+            };
+
+            /**
+             * @public
+             *
+             * @param int
+             * @return void
+             * @throws 1477846933
+             */
+            function setMaximalStackSize(stackSize) {
+                utility().assert('number' === $.type(stackSize), 'Invalid parameter "size"', 1477846933);
+                _applicationStateStackSize = stackSize;
+            };
+
+            /**
+             * @public
+             *
+             * @return int
+             */
+            function getMaximalStackSize() {
+                return _applicationStateStackSize;
+            };
+
+            /**
+             * @public
+             *
+             * @return int
+             */
+            function getCurrentStackSize() {
+                return _applicationStateStack.length;
+            };
+
+            /**
+             * @public
+             *
+             * @return object
+             */
+            function getCurrentStackPointer() {
+                return _applicationStateStackPointer;
+            };
+
+            /**
+             * @public
+             *
+             * @param int
+             * @return void
+             * @throws 1477852138
+             */
+            function setCurrentStackPointer(stackPointer) {
+                utility().assert('number' === $.type(stackPointer), 'Invalid parameter "size"', 1477852138);
+                if (stackPointer < 0) {
+                    _applicationStateStackPointer = 0;
+                } else if (stackPointer > _applicationStateStack.length - 1) {
+                    _applicationStateStackPointer = _applicationStateStack.length - 1;
+                } else {
+                    _applicationStateStackPointer = stackPointer;
+                }
+            };
+
+
+            /**
+             * @public
+             *
+             * @return void
+             */
+            function decrementCurrentStackPointer() {
+                setCurrentStackPointer(--_applicationStateStackPointer);
+            };
+
+            /**
+             * @public
+             *
+             * @return void
+             */
+            function incrementCurrentStackPointer() {
+                setCurrentStackPointer(++_applicationStateStackPointer);
+            };
+
+            /**
+             * Publish the public methods.
+             */
+            return {
+                add: add,
+                addAndReset: addAndReset,
+                getCurrentState: getCurrentState,
+                setCurrentState: setCurrentState,
+                getCurrentStackPointer: getCurrentStackPointer,
+                setCurrentStackPointer: setCurrentStackPointer,
+                decrementCurrentStackPointer: decrementCurrentStackPointer,
+                incrementCurrentStackPointer: incrementCurrentStackPointer,
+                setMaximalStackSize: setMaximalStackSize,
+                getMaximalStackSize: getMaximalStackSize,
+                getCurrentStackSize: getCurrentStackSize
+            };
+        };
+
+        /**
+         * Publish the public methods.
+         * Implements the "Revealing Module Pattern".
+         */
+        return {
+            getDataBackend: dataBackend,
+            getFactory: factory,
+            getPublisherSubscriber: publisherSubscriber,
+            getRepository: repository,
+            getUtility: utility,
+            getPropertyValidationService: propertyValidationService,
+            getRunningAjaxRequest: getRunningAjaxRequest,
+            getApplicationStateStack: getApplicationStateStack
+        };
+    })($);
+});
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/Helper.js b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/Helper.js
new file mode 100644
index 0000000000000000000000000000000000000000..c0969bd6b3732cb68e040057bee48cbdc3deb806
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/Helper.js
@@ -0,0 +1,310 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/Form/Backend/FormEditor/Helper
+ */
+define(['jquery'], function($) {
+        'use strict';
+
+    return (function($) {
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _formEditorApp = null;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _configuration = {};
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _defaultConfiguration = {
+            domElementClassNames: {
+                active: 'active',
+                buttonCollectionElementRemove: 't3-form-collection-element-remove-button',
+                buttonFormEditor: 't3-form-button',
+                disabled: 'disabled',
+                hidden: 'hidden',
+                icon: 't3-form-icon',
+                jQueryUiStateDisabled: 'ui-state-disabled',
+                sortableHover: 'sortable-hover'
+            },
+            domElementDataAttributeNames: {
+                elementIdentifier: 'data-element-identifier-path',
+                identifier: 'data-identifier',
+                template: 'data-template-name',
+                templateProperty: 'data-template-property'
+            },
+            domElementSelectorPattern: {
+                bracesWithKey: '[{0}]',
+                bracesWithKeyValue: '[{0}="{1}"]',
+                class: '.{0}',
+                id: '#{0}',
+                keyValue: '{0}="{1}"'
+            }
+        };
+
+        /* *************************************************************
+         * Private Methodes
+         * ************************************************************/
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getFormEditorApp() {
+            return _formEditorApp;
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getUtility() {
+            return getFormEditorApp().getUtility();
+        };
+
+        /**
+         * @private
+         *
+         * @param mixed test
+         * @param string message
+         * @param int messageCode
+         * @return void
+         */
+        function assert(test, message, messageCode) {
+            return getFormEditorApp().assert(test, message, messageCode);
+        };
+
+        /* *************************************************************
+         * Public Methodes
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return this
+         * @throws 1478950623
+         */
+        function setConfiguration(configuration) {
+            assert('object' === $.type(configuration), 'Invalid parameter "configuration"', 1478950623);
+            _configuration = $.extend(true, _defaultConfiguration, configuration);
+            return this;
+        };
+
+        /**
+         * @public
+         *
+         * @param string
+         * @param array
+         * @return string
+         * @throws 1478801251
+         * @throws 1478801252
+         */
+        function buildDomElementSelectorHelper(patternIdentifier, replacements) {
+            var newString;
+            assert(
+                !getUtility().isUndefinedOrNull(_configuration['domElementSelectorPattern'][patternIdentifier]),
+                'Invalid parameter "patternIdentifier" (' + patternIdentifier + ')',
+                1478801251
+            );
+            assert('array' === $.type(replacements), 'Invalid parameter "replacements"', 1478801252);
+
+            newString = _configuration['domElementSelectorPattern'][patternIdentifier];
+            for (var i = 0, len = replacements.length; i < len; ++i) {
+                newString = newString.replace('{' + i + '}', replacements[i]);
+            }
+            return newString;
+        };
+
+        /**
+         * @public
+         *
+         * @param string
+         * @param array
+         * @return string
+         * @throws 1478372374
+         */
+        function getDomElementSelector(selectorIdentifier, args) {
+            assert(
+                !getUtility().isUndefinedOrNull(_configuration['domElementSelectorPattern'][selectorIdentifier]),
+                'Invalid parameter "selectorIdentifier" (' + selectorIdentifier + ')',
+                1478372374
+            );
+            return buildDomElementSelectorHelper(selectorIdentifier, args);
+        };
+
+        /**
+         * @public
+         *
+         * @param string
+         * @param bool
+         * @return string
+         * @throws 1478803906
+         */
+        function getDomElementClassName(classNameIdentifier, asSelector) {
+            var className;
+            assert(
+                !getUtility().isUndefinedOrNull(_configuration['domElementClassNames'][classNameIdentifier]),
+                'Invalid parameter "classNameIdentifier" (' + classNameIdentifier + ')',
+                1478803906
+            );
+
+            className = _configuration['domElementClassNames'][classNameIdentifier];
+            if (!!asSelector) {
+                className = getDomElementSelector('class', [className]);
+            }
+            return className;
+        };
+
+        /**
+         * @public
+         *
+         * @param string
+         * @param bool
+         * @return string
+         * @throws 1479251518
+         */
+        function getDomElementIdName(idNameIdentifier, asSelector) {
+            var idName;
+            assert(
+                !getUtility().isUndefinedOrNull(_configuration['domElementIdNames'][idNameIdentifier]),
+                'Invalid parameter "domElementIdNames" (' + idNameIdentifier + ')',
+                1479251518
+            );
+
+            idName = _configuration['domElementIdNames'][idNameIdentifier];
+            if (!!asSelector) {
+                idName = getDomElementSelector('id', [idName]);
+            }
+            return idName;
+        };
+
+        /**
+         * @public
+         *
+         * @param string
+         * @param bool
+         * @return string
+         * @throws 1478806884
+         */
+        function getDomElementDataAttributeValue(dataAttributeValueIdentifier) {
+            assert(
+                !getUtility().isUndefinedOrNull(_configuration['domElementDataAttributeValues'][dataAttributeValueIdentifier]),
+                'Invalid parameter "dataAttributeValueIdentifier" (' + dataAttributeValueIdentifier + ')',
+                1478806884
+            );
+            return _configuration['domElementDataAttributeValues'][dataAttributeValueIdentifier];
+        };
+
+        /**
+         * @public
+         *
+         * @param string
+         * @param string
+         * @param array
+         * @return string
+         * @throws 1478808035
+         */
+        function getDomElementDataAttribute(dataAttributeIdentifier, selectorIdentifier, additionalSelectorArgs) {
+            assert(
+                !getUtility().isUndefinedOrNull(_configuration['domElementDataAttributeNames'][dataAttributeIdentifier]),
+                'Invalid parameter "dataAttributeIdentifier" (' + dataAttributeIdentifier + ')',
+                1478808035
+            );
+
+            if (getUtility().isUndefinedOrNull(selectorIdentifier)) {
+                return _configuration['domElementDataAttributeNames'][dataAttributeIdentifier];
+            }
+
+            additionalSelectorArgs = additionalSelectorArgs || [];
+            return getDomElementSelector(
+                selectorIdentifier,
+                [_configuration['domElementDataAttributeNames'][dataAttributeIdentifier]].concat(additionalSelectorArgs)
+            );
+        };
+
+        /**
+         * @public
+         *
+         * Return a string like [data-identifier="someValue"]
+         * 
+         * @return string
+         */
+        function getDomElementDataIdentifierSelector(dataAttributeValueIdentifier) {
+            return getDomElementDataAttribute('identifier', 'bracesWithKeyValue', [getDomElementDataAttributeValue(dataAttributeValueIdentifier)]);
+        };
+
+        /**
+         * @public
+         *
+         * @param string
+         * @return object
+         */
+        function getTemplate(templateName) {
+            return $(getDomElementDataAttribute('template', 'bracesWithKeyValue', [getDomElementDataAttributeValue(templateName)]));
+        };
+
+        /**
+         * @public
+         *
+         * @param string
+         * @param object
+         * @return object
+         */
+        function getTemplatePropertyDomElement(templatePropertyName, templateDomElement) {
+            return $(getDomElementDataAttribute('templateProperty', 'bracesWithKeyValue', [templatePropertyName]), $(templateDomElement));
+        };
+
+        /**
+         * @public
+         *
+         * @param object formEditorApp
+         * @return void
+         */
+        function bootstrap(formEditorApp) {
+            _formEditorApp = formEditorApp;
+        };
+
+        /**
+         * Publish the public methods.
+         * Implements the "Revealing Module Pattern".
+         */
+        return {
+            bootstrap: bootstrap,
+            buildDomElementSelectorHelper: buildDomElementSelectorHelper,
+            getDomElementClassName: getDomElementClassName,
+            getDomElementIdName: getDomElementIdName,
+            getDomElementDataAttribute: getDomElementDataAttribute,
+            getDomElementDataAttributeValue: getDomElementDataAttributeValue,
+            getDomElementDataIdentifierSelector: getDomElementDataIdentifierSelector,
+            getDomElementSelector: getDomElementSelector,
+            getTemplate: getTemplate,
+            getTemplatePropertyDomElement: getTemplatePropertyDomElement,
+            setConfiguration: setConfiguration
+        };
+    })($);
+});
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/InspectorComponent.js b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/InspectorComponent.js
new file mode 100644
index 0000000000000000000000000000000000000000..ae0855e02bd8c0369cd4c8467b2b6c9978276eca
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/InspectorComponent.js
@@ -0,0 +1,1777 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/Form/Backend/FormEditor/InspectorComponent
+ */
+
+/**
+ * Add legacy functions to be accessible in the global scope.
+ * This is needed by TYPO3/CMS/Recordlist/ElementBrowser
+ */
+var setFormValueFromBrowseWin;
+
+define(['jquery',
+        'TYPO3/CMS/Form/Backend/FormEditor/Helper',
+        'TYPO3/CMS/Backend/Icons',
+        'TYPO3/CMS/Backend/Notification',
+        'TYPO3/CMS/Form/Backend/Vendor/jquery.mjs.nestedSortable'
+        ], function($, Helper, Icons, Notification) {
+        'use strict';
+
+    return (function($, Helper, Icons, Notification) {
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _configuration = null;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _defaultConfiguration = {
+            domElementClassNames: {
+                buttonFormElementRemove: 't3-form-remove-element-button',
+                collectionElement: 't3-form-collection-element',
+                finisherEditorPrefix: 't3-form-inspector-finishers-editor-',
+                inspectorEditor: 'form-editor',
+                validatorEditorPrefix: 't3-form-inspector-validators-editor-'
+            },
+            domElementDataAttributeNames: {
+                contentElementSelectorTarget: 'data-insert-target',
+                finisher: 'data-finisher-identifier',
+                validator: 'data-validator-identifier'
+            },
+            domElementDataAttributeValues: {
+                collapse: 'actions-view-table-expand',
+                editorControlsWrapper: 'inspectorEditorControlsWrapper',
+                formElementHeaderEditor: 'inspectorFormElementHeaderEditor',
+                iconPage: 'apps-pagetree-page-default',
+                iconTtContent: 'mimetypes-x-content-text',
+                inspector: 'inspector',
+                'Inspector-CheckboxEditor': 'Inspector-CheckboxEditor',
+                'Inspector-CollectionElementHeaderEditor': 'Inspector-CollectionElementHeaderEditor',
+                'Inspector-FinishersEditor': 'Inspector-FinishersEditor',
+                'Inspector-FormElementHeaderEditor': 'Inspector-FormElementHeaderEditor',
+                'Inspector-PropertyGridEditor': 'Inspector-PropertyGridEditor',
+                'Inspector-RemoveElementEditor': 'Inspector-RemoveElementEditor',
+                'Inspector-RequiredValidatorEditor': 'Inspector-RequiredValidatorEditor',
+                'Inspector-SingleSelectEditor': 'Inspector-SingleSelectEditor',
+                'Inspector-TextareaEditor': 'Inspector-TextareaEditor',
+                'Inspector-TextEditor': 'Inspector-TextEditor',
+                'Inspector-Typo3WinBrowserEditor': 'Inspector-Typo3WinBrowserEditor',
+                'Inspector-ValidatorsEditor': 'Inspector-ValidatorsEditor',
+                inspectorFinishers: 'inspectorFinishers',
+                inspectorValidators: 'inspectorValidators',
+                propertyGridEditorAddRow: 'addRow',
+                propertyGridEditorAddRowItem: 'addRowItem',
+                propertyGridEditorContainer: 'propertyGridContainer',
+                propertyGridEditorDeleteRow: 'deleteRow',
+                propertyGridEditorLabel: 'label',
+                propertyGridEditorRowItem: 'rowItem',
+                propertyGridEditorSelectValue: 'selectValue',
+                propertyGridEditorSortRow: 'sortRow',
+                propertyGridEditorValue: 'value'
+            },
+            domElementIdNames: {
+                finisherPrefix: 't3-form-inspector-finishers-',
+                validatorPrefix: 't3-form-inspector-validators-'
+            },
+            isSortable: true
+        };
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _formEditorApp = null;
+
+        /* *************************************************************
+         * Private Methodes
+         * ************************************************************/
+
+        /**
+         * @private
+         *
+         * @return void
+         * @throws 1478268638
+         */
+        function _helperSetup() {
+            assert('function' === $.type(Helper.bootstrap),
+                'The view model helper does not implement the method "bootstrap"',
+                1478268638
+            );
+            Helper.bootstrap(getFormEditorApp());
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getFormEditorApp() {
+            return _formEditorApp;
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getViewModel() {
+            return getFormEditorApp().getViewModel();
+        };
+
+        /**
+         * @private
+         *
+         * @param object
+         * @return object
+         */
+        function getHelper(configuration) {
+            if (getUtility().isUndefinedOrNull(configuration)) {
+                return Helper.setConfiguration(_configuration);
+            }
+            return Helper.setConfiguration(configuration);
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getUtility() {
+            return getFormEditorApp().getUtility();
+        };
+
+        /**
+         * @private
+         *
+         * @param mixed test
+         * @param string message
+         * @param int messageCode
+         * @return void
+         */
+        function assert(test, message, messageCode) {
+            return getFormEditorApp().assert(test, message, messageCode);
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getCurrentlySelectedFormElement() {
+            return getFormEditorApp().getCurrentlySelectedFormElement();
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getRootFormElement() {
+            return getFormEditorApp().getRootFormElement();
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getPublisherSubscriber() {
+            return getFormEditorApp().getPublisherSubscriber();
+        };
+
+        /**
+         * @private
+         *
+         * @param object
+         * @param string
+         * @return mixed
+         */
+        function getFormElementDefinition(formElement, formElementDefinitionKey) {
+            return getFormEditorApp().getFormElementDefinition(formElement, formElementDefinitionKey);
+        };
+
+        /**
+         * @private
+         *
+         * @param object
+         * @param object
+         * @param string
+         * @param string
+         * @return void
+         * @publish view/inspector/editor/insert/perform
+         */
+        function _renderEditorDispatcher(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
+            switch (editorConfiguration['templateName']) {
+                case 'Inspector-FormElementHeaderEditor':
+                    renderFormElementHeaderEditor(
+                        editorConfiguration,
+                        editorHtml,
+                        collectionElementIdentifier,
+                        collectionName
+                    );
+                    break;
+                case 'Inspector-CollectionElementHeaderEditor':
+                    renderCollectionElementHeaderEditor(
+                        editorConfiguration,
+                        editorHtml,
+                        collectionElementIdentifier,
+                        collectionName
+                    );
+                    break;
+                case 'Inspector-TextEditor':
+                    renderTextEditor(
+                        editorConfiguration,
+                        editorHtml,
+                        collectionElementIdentifier,
+                        collectionName
+                    );
+                    break;
+                case 'Inspector-FinishersEditor':
+                    renderCollectionElementSelectionEditor(
+                        'finishers',
+                        editorConfiguration,
+                        editorHtml,
+                        collectionElementIdentifier,
+                        collectionName
+                    );
+                    break;
+                case 'Inspector-ValidatorsEditor':
+                    renderCollectionElementSelectionEditor(
+                        'validators',
+                        editorConfiguration,
+                        editorHtml,
+                        collectionElementIdentifier,
+                        collectionName
+                    );
+                    break;
+                case 'Inspector-RemoveElementEditor':
+                    renderRemoveElementEditor(
+                        editorConfiguration,
+                        editorHtml,
+                        collectionElementIdentifier,
+                        collectionName
+                    );
+                    break;
+                case 'Inspector-RequiredValidatorEditor':
+                    renderRequiredValidatorEditor(
+                        editorConfiguration,
+                        editorHtml,
+                        collectionElementIdentifier,
+                        collectionName
+                    );
+                    break;
+                case 'Inspector-CheckboxEditor':
+                    renderCheckboxEditor(
+                        editorConfiguration,
+                        editorHtml,
+                        collectionElementIdentifier,
+                        collectionName
+                    );
+                    break;
+                case 'Inspector-SingleSelectEditor':
+                    renderSingleSelectEditor(
+                        editorConfiguration,
+                        editorHtml,
+                        collectionElementIdentifier,
+                        collectionName
+                    );
+                    break;
+                case 'Inspector-PropertyGridEditor':
+                    renderPropertyGridEditor(
+                        editorConfiguration,
+                        editorHtml,
+                        collectionElementIdentifier,
+                        collectionName
+                    );
+                    break;
+                case 'Inspector-TextareaEditor':
+                    renderTextareaEditor(
+                        editorConfiguration,
+                        editorHtml,
+                        collectionElementIdentifier,
+                        collectionName
+                    );
+                    break;
+                case 'Inspector-Typo3WinBrowserEditor':
+                    renderTypo3WinBrowserEditor(
+                        editorConfiguration,
+                        editorHtml,
+                        collectionElementIdentifier,
+                        collectionName
+                    );
+                    break;
+            }
+            getPublisherSubscriber().publish('view/inspector/editor/insert/perform', [
+                editorConfiguration, editorHtml, collectionElementIdentifier, collectionName
+            ]);
+        };
+
+        /**
+         * @private
+         *
+         * opens a popup window with the element browser
+         *
+         * @param string mode
+         * @param string params
+         * @param int width
+         * @param int height
+         */
+        function _openTypo3WinBrowser(mode, params, width, height) {
+            var openedPopupWindow, url;
+            url = TYPO3.settings.FormEditor.typo3WinBrowserUrl
+                + '&mode=' + mode + '&bparams=' + params;
+            openedPopupWindow = window.open(
+                url,
+                'Typo3WinBrowser',
+                'height=' + height + ',width=' + width + ',status=0,menubar=0,resizable=1,scrollbars=1'
+            );
+            openedPopupWindow.focus();
+        };
+
+        /**
+         * @private
+         *
+         * @param string
+         * @param string
+         * @return object
+         */
+        function _getCollectionElementClass(collectionName, collectionElementIdentifier) {
+            if (collectionName === 'finishers') {
+                return getHelper()
+                    .getDomElementClassName('finisherEditorPrefix') + collectionElementIdentifier;
+            } else {
+                return getHelper()
+                    .getDomElementClassName('validatorEditorPrefix') + collectionElementIdentifier;
+            }
+        };
+
+        /**
+         * @private
+         *
+         * @param string
+         * @param string
+         * @param bool
+         * @return object
+         */
+        function _getCollectionElementId(collectionName, collectionElementIdentifier, asSelector) {
+            if (collectionName === 'finishers') {
+                return getHelper()
+                    .getDomElementIdName('finisherPrefix', asSelector) + collectionElementIdentifier;
+            } else {
+                return getHelper()
+                    .getDomElementIdName('validatorPrefix', asSelector) + collectionElementIdentifier;
+            }
+        };
+
+        /**
+         * @private
+         *
+         * @param object
+         * @param string
+         * @return void
+         */
+        function _addSortableCollectionElementsEvents(sortableDomElement, collectionName) {
+            sortableDomElement.addClass(getHelper().getDomElementClassName('sortable')).sortable({
+                revert: 'true',
+                items: getHelper().getDomElementClassName('collectionElement', true),
+                cancel: getHelper().getDomElementClassName('jQueryUiStateDisabled', true) + ',input,select',
+                delay: 200,
+                update: function(e, o) {
+                    var dataAttributeName, nextCollectionElementIdentifier, movedCollectionElementIdentifier, previousCollectionElementIdentifier;
+
+                    if (collectionName === 'finishers') {
+                        dataAttributeName = getHelper().getDomElementDataAttribute('finisher');
+                    } else {
+                        dataAttributeName = getHelper().getDomElementDataAttribute('validator');
+                    }
+
+                    movedCollectionElementIdentifier = $(o.item).attr(dataAttributeName);
+                    previousCollectionElementIdentifier = $(o.item)
+                        .prevAll(getHelper().getDomElementClassName('collectionElement', true))
+                        .first()
+                        .attr(dataAttributeName);
+                    nextCollectionElementIdentifier = $(o.item)
+                        .nextAll(getHelper().getDomElementClassName('collectionElement', true))
+                        .first()
+                        .attr(dataAttributeName);
+
+                    getPublisherSubscriber().publish('view/inspector/collectionElements/dnd/update', [
+                        movedCollectionElementIdentifier,
+                        previousCollectionElementIdentifier,
+                        nextCollectionElementIdentifier,
+                        collectionName
+                    ]);
+                }
+            });
+        };
+
+        /**
+         * @private
+         *
+         * @param object editorHtml
+         * @param bool multiSelection
+         * @param string propertyPath
+         * @param string propertyPathPrefix
+         * @return void
+         */
+        function _setPropertyGridData(editorHtml, multiSelection, propertyPath, propertyPathPrefix) {
+            var defaultValue, newPropertyData;
+
+            if (multiSelection) {
+                defaultValue = [];
+
+                $(  getHelper().getDomElementDataIdentifierSelector('propertyGridEditorContainer') + ' ' +
+                    getHelper().getDomElementDataIdentifierSelector('propertyGridEditorSelectValue') + ':checked',
+                    $(editorHtml)
+                ).each(function(i) {
+                    defaultValue.push(
+                        $(this)
+                            .closest(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'))
+                            .find(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorValue'))
+                            .val()
+                        );
+                });
+                getCurrentlySelectedFormElement().set(propertyPathPrefix + 'defaultValue', defaultValue);
+            } else {
+                getCurrentlySelectedFormElement().set(
+                    propertyPathPrefix + 'defaultValue',
+                    $(
+                        getHelper().getDomElementDataIdentifierSelector('propertyGridEditorContainer') + ' ' +
+                        getHelper().getDomElementDataIdentifierSelector('propertyGridEditorSelectValue') + ':checked',
+                        $(editorHtml)
+                    ).first()
+                        .closest(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'))
+                        .find(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorValue'))
+                        .val(),
+                    true
+                );
+            }
+
+            newPropertyData = [];
+            $(
+                getHelper().getDomElementDataIdentifierSelector('propertyGridEditorContainer') + ' ' +
+                getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'),
+                $(editorHtml)
+            ).each(function(i) {
+                var value, label, tmpObject;
+
+                value = $(this)
+                    .find(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorValue'))
+                    .val();
+                label = $(this)
+                    .find(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorLabel'))
+                    .val();
+
+                if ('' === value) {
+                    value = label;
+                }
+
+                tmpObject = {};
+                tmpObject[value] = label;
+                newPropertyData.push({
+                    _label: label,
+                    _value: value
+                });
+            });
+
+            getCurrentlySelectedFormElement().set(propertyPathPrefix + propertyPath, newPropertyData);
+        };
+
+        /**
+         * @private
+         *
+         * @param object
+         * @return object
+         */
+        function _getEditorControlsWrapperDomElement(editorDomElement) {
+            return $(getHelper().getDomElementDataIdentifierSelector('editorControlsWrapper'), $(editorDomElement));
+        };
+
+        /**
+         * @private
+         *
+         * @param string
+         * @param object
+         * @return void
+         */
+        function _validateCollectionElement(propertyPath, editorHtml) {
+            var hasError, propertyPrefix, validationResults;
+
+            validationResults = getFormEditorApp().validateCurrentlySelectedFormElementProperty(propertyPath);
+
+            if (validationResults.length > 0) {
+                getHelper()
+                    .getTemplatePropertyDomElement('validationErrors', editorHtml)
+                    .text(validationResults[0]);
+                getViewModel().setElementValidationErrorClass(
+                    getHelper().getTemplatePropertyDomElement('validationErrors', editorHtml)
+                );
+                getViewModel().setElementValidationErrorClass(
+                    _getEditorControlsWrapperDomElement(editorHtml),
+                    'hasError'
+                );
+            } else {
+                getHelper().getTemplatePropertyDomElement('validationErrors', editorHtml).text('');
+                getViewModel().removeElementValidationErrorClass(
+                    getHelper().getTemplatePropertyDomElement('validationErrors', editorHtml)
+                );
+                getViewModel().removeElementValidationErrorClass(
+                    _getEditorControlsWrapperDomElement(editorHtml),
+                    'hasError'
+                );
+            }
+
+            validationResults = getFormEditorApp().validateFormElement(getCurrentlySelectedFormElement());
+            propertyPrefix = propertyPath.split('.');
+            propertyPrefix = propertyPrefix[0] + '.' + propertyPrefix[1];
+
+            hasError = false;
+            for (var i = 0, len = validationResults.length; i < len; ++i) {
+                if (
+                    validationResults[i]['propertyPath'].indexOf(propertyPrefix, 0) === 0
+                    && validationResults[i]['validationResults']
+                    && validationResults[i]['validationResults'].length > 0
+                ) {
+                    hasError = true;
+                    break;
+                }
+            }
+
+            if (hasError) {
+                getViewModel().setElementValidationErrorClass(
+                    _getEditorControlsWrapperDomElement(editorHtml).closest(getHelper().getDomElementClassName('collectionElement', true))
+                );
+            } else {
+                getViewModel().removeElementValidationErrorClass(
+                    _getEditorControlsWrapperDomElement(editorHtml).closest(getHelper().getDomElementClassName('collectionElement', true))
+                );
+            }
+        };
+
+        /* *************************************************************
+         * Public Methodes
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * callback from TYPO3/CMS/Recordlist/ElementBrowser
+         *
+         * @param string fieldReference
+         * @param string elValue
+         * @param string elName
+         * @return void
+         */
+        setFormValueFromBrowseWin = function(fieldReference, elValue, elName) {
+            var result;
+            result = elValue.split('_');
+            
+            $(getHelper().getDomElementDataAttribute('contentElementSelectorTarget', 'bracesWithKeyValue', [fieldReference]))
+                .val(result.pop())
+                .trigger('paste');
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function getInspectorDomElement() {
+            return $(getHelper().getDomElementDataIdentifierSelector('inspector'));
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function getFinishersContainerDomElement() {
+            return $(getHelper().getDomElementDataIdentifierSelector('inspectorFinishers'), getInspectorDomElement());
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function getValidatorsContainerDomElement() {
+            return $(getHelper().getDomElementDataIdentifierSelector('inspectorValidators'), getInspectorDomElement());
+        };
+
+        /**
+         * @public
+         *
+         * @param string
+         * @param string
+         * @return object
+         */
+        function getCollectionElementDomElement(collectionName, collectionElementIdentifier) {
+            if (collectionName === 'finishers') {
+                return $(getHelper().getDomElementDataAttribute(
+                            'finisher',
+                            'bracesWithKeyValue',
+                            [collectionElementIdentifier]
+                        ), getFinishersContainerDomElement());
+            } else {
+                return $(getHelper().getDomElementDataAttribute(
+                        'validator',
+                        'bracesWithKeyValue',
+                        [collectionElementIdentifier]
+                    ), getValidatorsContainerDomElement());
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param function
+         * @return void
+         */
+        function renderEditors(formElement, callback) {
+            var formElementTypeDefinition;
+            if (getUtility().isUndefinedOrNull(formElement)) {
+                formElement = getCurrentlySelectedFormElement();
+            }
+
+            getInspectorDomElement().off().empty();
+
+            formElementTypeDefinition = getFormElementDefinition(formElement);
+            if ('array' !== $.type(formElementTypeDefinition['editors'])) {
+                return;
+            }
+
+            for (var i = 0, len = formElementTypeDefinition['editors'].length; i < len; ++i) {
+                var html, template;
+
+                template = getHelper()
+                    .getTemplate(formElementTypeDefinition['editors'][i]['templateName'])
+                    .clone();
+                if (!template.length) {
+                    continue;
+                }
+                html = $(template.html());
+
+                $(html)
+                    .first()
+                    .addClass(getHelper().getDomElementClassName('inspectorEditor'));
+                getInspectorDomElement().append($(html));
+
+                _renderEditorDispatcher(formElementTypeDefinition['editors'][i], html);
+            }
+
+            if ('function' === $.type(callback)) {
+                callback();
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param string collectionName
+         * @param string collectionElementIdentifier
+         * @return void
+         * @publish view/inspector/collectionElements/dnd/update
+         * @throws 1478354853
+         * @throws 1478354854
+         */
+        function renderCollectionElementEditors(collectionName, collectionElementIdentifier) {
+            var collapseWrapper, collectionContainer, collectionContainerElementWrapper, collectionElementConfiguration, collectionElementEditorsLength;
+
+            assert(
+                getUtility().isNonEmptyString(collectionName),
+                'Invalid parameter "collectionName"',
+                1478354853
+            );
+            assert(
+                getUtility().isNonEmptyString(collectionElementIdentifier),
+                'Invalid parameter "collectionElementIdentifier"',
+                1478354854
+            );
+
+            collectionElementConfiguration = getFormEditorApp().getPropertyCollectionElementConfiguration(
+                collectionElementIdentifier,
+                collectionName
+            );
+            if ('array' !== $.type(collectionElementConfiguration['editors'])) {
+                return;
+            }
+
+            collectionContainerElementWrapper = $('<div></div>').
+                addClass(getHelper().getDomElementClassName('collectionElement'));
+            if (collectionName === 'finishers') {
+                collectionContainer = getFinishersContainerDomElement();
+                collectionContainerElementWrapper
+                    .attr(getHelper().getDomElementDataAttribute('finisher'), collectionElementIdentifier);
+            } else {
+                collectionContainer = getValidatorsContainerDomElement();
+                collectionContainerElementWrapper
+                    .attr(getHelper().getDomElementDataAttribute('validator'), collectionElementIdentifier);
+            }
+            collectionContainer.append(collectionContainerElementWrapper);
+
+            collectionElementEditorsLength = collectionElementConfiguration['editors'].length;
+            if (
+                collectionElementEditorsLength > 0
+                && collectionElementConfiguration['editors'][0]['identifier'] === 'header'
+            ) {
+                collapseWrapper = $('<div role="tabpanel"></div>')
+                    .addClass('panel-collapse collapse')
+                    .prop('id', _getCollectionElementId(
+                        collectionName,
+                        collectionElementIdentifier
+                    ));
+            }
+
+            for (var i = 0; i < collectionElementEditorsLength; ++i) {
+                var html, template;
+
+                template = getHelper()
+                    .getTemplate(collectionElementConfiguration['editors'][i]['templateName'])
+                    .clone();
+                if (!template.length) {
+                    continue;
+                }
+                html = $(template.html());
+
+                $(html).first()
+                    .addClass(_getCollectionElementClass(
+                        collectionName,
+                        collectionElementConfiguration['editors'][i]['identifier']
+                    ))
+                    .addClass(getHelper().getDomElementClassName('inspectorEditor'));
+
+                if (i === 0 && collapseWrapper) {
+                    getCollectionElementDomElement(collectionName, collectionElementIdentifier)
+                        .append(html)
+                        .append(collapseWrapper);
+                } else if (
+                    i === (collectionElementEditorsLength - 1)
+                    && collapseWrapper
+                    && collectionElementConfiguration['editors'][i]['identifier'] === 'removeButton'
+                ) {
+                    getCollectionElementDomElement(collectionName, collectionElementIdentifier).append(html);
+                } else if (i > 0 && collapseWrapper) {
+                    collapseWrapper.append(html);
+                } else {
+                    getCollectionElementDomElement(collectionName, collectionElementIdentifier).append(html);
+                }
+
+                _renderEditorDispatcher(
+                    collectionElementConfiguration['editors'][i],
+                    html,
+                    collectionElementIdentifier,
+                    collectionName
+                );
+            }
+
+            if (
+                collectionElementEditorsLength === 2
+                && collectionElementConfiguration['editors'][0]['identifier'] === 'header'
+                && collectionElementConfiguration['editors'][1]['identifier'] === 'removeButton'
+            ) {
+                $(getHelper().getDomElementDataIdentifierSelector('collapse'), collectionContainerElementWrapper).remove();
+            }
+
+            if (_configuration['isSortable']) {
+                _addSortableCollectionElementsEvents(collectionContainer, collectionName);
+            }
+        };
+
+       /**
+         * @public
+         *
+         * @string collectionName
+         * @param object editorConfiguration
+         * @param object editorHtml
+         * @return void
+         * @publish view/inspector/collectionElement/existing/selected
+         * @publish view/inspector/collectionElement/new/selected
+         * @throws 1475423098
+         * @throws 1475423099
+         * @throws 1475423100
+         * @throws 1475423101
+         * @throws 1478362968
+         */
+        function renderCollectionElementSelectionEditor(collectionName, editorConfiguration, editorHtml) {
+            var alreadySelectedCollectionElements, selectElement, collectionContainer;
+            assert(
+                getUtility().isNonEmptyString(collectionName),
+                'Invalid configuration "collectionName"',
+                1478362968
+            );
+            assert(
+                'object' === $.type(editorConfiguration),
+                'Invalid parameter "editorConfiguration"',
+                1475423098
+            );
+            assert(
+                'object' === $.type(editorHtml),
+                'Invalid parameter "editorHtml"',
+                1475423099
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['label']),
+                'Invalid configuration "label"',
+                1475423100
+            );
+            assert(
+                'array' === $.type(editorConfiguration['selectOptions']),
+                'Invalid configuration "selectOptions"',
+                1475423101
+            );
+
+            if (collectionName === 'finishers') {
+                collectionContainer = getFinishersContainerDomElement();
+                alreadySelectedCollectionElements = getRootFormElement().get(collectionName);
+            } else {
+                collectionContainer = getValidatorsContainerDomElement();
+                alreadySelectedCollectionElements = getCurrentlySelectedFormElement().get(collectionName);
+            }
+
+            collectionContainer.off().empty();
+
+            getHelper().getTemplatePropertyDomElement('label', editorHtml).text(editorConfiguration['label']);
+            selectElement = getHelper().getTemplatePropertyDomElement('selectOptions', editorHtml);
+
+            if (!getUtility().isUndefinedOrNull(alreadySelectedCollectionElements)) {
+                for (var i = 0, len = alreadySelectedCollectionElements.length; i < len; ++i) {
+                    getPublisherSubscriber().publish('view/inspector/collectionElement/existing/selected', [
+                        alreadySelectedCollectionElements[i]['identifier'],
+                        collectionName
+                    ]);
+                }
+            }
+
+            for (var i = 0, len1 = editorConfiguration['selectOptions'].length; i < len1; ++i) {
+                var appendOption = true;
+                if (!getUtility().isUndefinedOrNull(alreadySelectedCollectionElements)) {
+                    for (var j = 0, len2 = alreadySelectedCollectionElements.length; j < len2; ++j) {
+                        if (alreadySelectedCollectionElements[j]['identifier'] === editorConfiguration['selectOptions'][i]['value']) {
+                            appendOption = false;
+                            break;
+                        }
+                    }
+                }
+                if (appendOption) {
+                    selectElement.append(new Option(
+                        editorConfiguration['selectOptions'][i]['label'],
+                        editorConfiguration['selectOptions'][i]['value']
+                    ));
+                }
+            }
+
+            selectElement.on('change', function() {
+                if ($(this).val() !== '') {
+                    var value = $(this).val();
+                    $('option[value="' + value + '"]', $(this)).remove();
+
+                    getFormEditorApp().getPublisherSubscriber().publish(
+                        'view/inspector/collectionElement/new/selected',
+                        [value, collectionName]
+                    );
+                }
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @param object editorConfiguration
+         * @param object editorHtml
+         * @param string collectionElementIdentifier
+         * @param string collectionName
+         * @return void
+         * @throws 1475421525
+         * @throws 1475421526
+         * @throws 1475421527
+         * @throws 1475421528
+         */
+        function renderFormElementHeaderEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
+            assert('object' === $.type(editorConfiguration), 'Invalid parameter "editorConfiguration"', 1475421525);
+            assert('object' === $.type(editorHtml), 'Invalid parameter "editorHtml"', 1475421526);
+
+            Icons.getIcon(
+                getFormElementDefinition(getCurrentlySelectedFormElement(), 'iconIdentifier'),
+                Icons.sizes.small,
+                null,
+                Icons.states.default
+            ).done(function(icon) {
+                getHelper().getTemplatePropertyDomElement('header-label', editorHtml)
+                    .append($(icon).addClass(getHelper().getDomElementClassName('icon')))
+                    .append(buildTitleByFormElement());
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @param object editorConfiguration
+         * @param object editorHtml
+         * @param string collectionElementIdentifier
+         * @param string collectionName
+         * @return void
+         * @throws 1475421257
+         * @throws 1475421258
+         * @throws 1475421259
+         */
+        function renderCollectionElementHeaderEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
+            var collectionElementConfiguration, setData;
+
+            assert(
+                'object' === $.type(editorConfiguration),
+                'Invalid parameter "editorConfiguration"',
+                1475421258
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['label']),
+                'Invalid configuration "label"',
+                1475421257
+            );
+            assert(
+                'object' === $.type(editorHtml),
+                'Invalid parameter "editorHtml"',
+                1475421259
+            );
+
+            setData = function(icon) {
+                getHelper()
+                    .getTemplatePropertyDomElement('header-label', editorHtml)
+                    .prepend($(icon));
+
+                Icons.getIcon(
+                    getHelper().getDomElementDataAttributeValue('collapse'),
+                    Icons.sizes.small,
+                    null,
+                    Icons.states.default,
+                    Icons.markupIdentifiers.inline
+                ).done(function(icon) {
+                    var iconWrap;
+                    iconWrap = $('<a></a>')
+                        .attr('href', _getCollectionElementId(collectionName, collectionElementIdentifier, true))
+                        .attr('data-toggle', 'collapse')
+                        .attr('aria-expanded', 'true')
+                        .attr('aria-controls', _getCollectionElementId(collectionName, collectionElementIdentifier))
+                        .addClass('collapsed')
+                        .append($(icon));
+
+                    getHelper()
+                        .getTemplatePropertyDomElement('header-label', editorHtml)
+                        .prepend(iconWrap);
+                });
+            };
+
+            collectionElementConfiguration = getFormEditorApp().getFormEditorDefinition(collectionName, collectionElementIdentifier);
+            if (collectionName === 'validators') {
+                Icons.getIcon(
+                    collectionElementConfiguration['iconIdentifier'],
+                    Icons.sizes.small,
+                    null,
+                    Icons.states.default
+                ).done(function(icon) {
+                    setData(icon);
+                });
+            } else {
+                Icons.getIcon(
+                    collectionElementConfiguration['iconIdentifier'],
+                    Icons.sizes.small,
+                    null,
+                    Icons.states.default
+                ).done(function(icon) {
+                    setData(icon);
+                });
+            }
+
+            if (editorConfiguration['label']) {
+                getHelper().getTemplatePropertyDomElement('label', editorHtml).append(editorConfiguration['label']);
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param object editorConfiguration
+         * @param object editorHtml
+         * @param string collectionElementIdentifier
+         * @param string collectionName
+         * @return void
+         * @throws 1475421053
+         * @throws 1475421054
+         * @throws 1475421055
+         * @throws 1475421056
+         */
+        function renderTextEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
+            var propertyPath, propertyData;
+            assert(
+                'object' === $.type(editorConfiguration),
+                'Invalid parameter "editorConfiguration"',
+                1475421053
+            );
+            assert(
+                'object' === $.type(editorHtml),
+                'Invalid parameter "editorHtml"',
+                1475421054
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['label']),
+                'Invalid configuration "label"',
+                1475421055
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
+                'Invalid configuration "propertyPath"',
+                1475421056
+            );
+
+            getHelper()
+                .getTemplatePropertyDomElement('label', editorHtml)
+                .append(editorConfiguration['label']);
+            if (getUtility().isNonEmptyString(editorConfiguration['fieldExplanationText'])) {
+                getHelper()
+                    .getTemplatePropertyDomElement('fieldExplanationText', editorHtml)
+                    .text(editorConfiguration['fieldExplanationText']);
+            } else {
+                getHelper()
+                    .getTemplatePropertyDomElement('fieldExplanationText', editorHtml)
+                    .remove();
+            }
+
+            propertyPath = getFormEditorApp().buildPropertyPath(
+                editorConfiguration['propertyPath'],
+                collectionElementIdentifier,
+                collectionName
+            );
+            propertyData = getCurrentlySelectedFormElement().get(propertyPath);
+
+            _validateCollectionElement(propertyPath, editorHtml);
+
+            getHelper().getTemplatePropertyDomElement('propertyPath', editorHtml).val(propertyData);
+
+            getHelper().getTemplatePropertyDomElement('propertyPath', editorHtml).on('keyup paste', function() {
+                getCurrentlySelectedFormElement().set(propertyPath, $(this).val());
+                _validateCollectionElement(propertyPath, editorHtml);
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @param object editorConfiguration
+         * @param object editorHtml
+         * @param string collectionElementIdentifier
+         * @param string collectionName
+         * @return void
+         * @throws 1475421048
+         * @throws 1475421049
+         * @throws 1475421050
+         * @throws 1475421051
+         * @throws 1475421052
+         */
+        function renderSingleSelectEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
+            var propertyData, propertyPath, selectElement;
+            assert(
+                'object' === $.type(editorConfiguration),
+                'Invalid parameter "editorConfiguration"',
+                1475421048
+            );
+            assert(
+                'object' === $.type(editorHtml),
+                'Invalid parameter "editorHtml"',
+                1475421049
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['label']),
+                'Invalid configuration "label"',
+                1475421050
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
+                'Invalid configuration "propertyPath"',
+                1475421051
+            );
+            assert(
+                'array' === $.type(editorConfiguration['selectOptions']),
+                'Invalid configuration "selectOptions"',
+                1475421052
+            );
+
+            propertyPath = getFormEditorApp().buildPropertyPath(
+                editorConfiguration['propertyPath'],
+                collectionElementIdentifier,
+                collectionName
+            );
+
+            getHelper()
+                .getTemplatePropertyDomElement('label', editorHtml)
+                .append(editorConfiguration['label']);
+
+            selectElement = getHelper()
+                .getTemplatePropertyDomElement('selectOptions', editorHtml);
+
+            propertyData = getCurrentlySelectedFormElement().get(propertyPath);
+
+            for (var i = 0, len = editorConfiguration['selectOptions'].length; i < len; ++i) {
+                var option;
+
+                if (editorConfiguration['selectOptions'][i]['value'] === propertyData) {
+                    option = new Option(editorConfiguration['selectOptions'][i]['label'], i, false, true);
+                } else {
+                    option = new Option(editorConfiguration['selectOptions'][i]['label'], i);
+                }
+                $(option).data({value: editorConfiguration['selectOptions'][i]['value']});
+                selectElement.append(option);
+            }
+
+            selectElement.on('change', function() {
+                getCurrentlySelectedFormElement().set(propertyPath, $('option:selected', $(this)).data('value'));
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @param object editorConfiguration
+         * @param object editorHtml
+         * @param string collectionElementIdentifier
+         * @param string collectionName
+         * @return void
+         * @throws 1475419226
+         * @throws 1475419227
+         * @throws 1475419228
+         * @throws 1475419229
+         * @throws 1475419230
+         * @throws 1475419231
+         * @throws 1475419232
+         */
+        function renderPropertyGridEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
+            var addRowTemplate, defaultValue, multiSelection, propertyData, propertyPathPrefix, rowItemTemplate, setData;
+            assert(
+                'object' === $.type(editorConfiguration),
+                'Invalid parameter "editorConfiguration"',
+                1475419226
+            );
+            assert(
+                'object' === $.type(editorHtml),
+                'Invalid parameter "editorHtml"',
+                1475419227
+            );
+            assert(
+                'boolean' === $.type(editorConfiguration['enableAddRow']),
+                'Invalid configuration "enableAddRow"',
+                1475419228
+            );
+            assert(
+                'boolean' === $.type(editorConfiguration['enableDeleteRow']),
+                'Invalid configuration "enableDeleteRow"',
+                1475419230
+            );
+            assert(
+                'boolean' === $.type(editorConfiguration['isSortable']),
+                'Invalid configuration "isSortable"',
+                1475419229
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
+                'Invalid configuration "propertyPath"',
+                1475419231
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['label']),
+                'Invalid configuration "label"',
+                1475419232
+            );
+
+            getHelper().getTemplatePropertyDomElement('label', editorHtml).append(editorConfiguration['label']);
+            propertyPathPrefix = getFormEditorApp().buildPropertyPath(
+                undefined,
+                collectionElementIdentifier,
+                collectionName,
+                undefined,
+                true
+            );
+            if (getUtility().isNonEmptyString(propertyPathPrefix)) {
+                propertyPathPrefix = propertyPathPrefix + '.';
+            }
+
+            if (getUtility().isUndefinedOrNull(editorConfiguration['multiSelection'])) {
+                multiSelection = false;
+            } else {
+                multiSelection = !!editorConfiguration['multiSelection'];
+            }
+
+            rowItemTemplate = $(
+                getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'),
+                $(editorHtml)
+            ).clone();
+            $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'), $(editorHtml)).remove();
+
+            if (!!editorConfiguration['enableDeleteRow']) {
+                $(  getHelper().getDomElementDataIdentifierSelector('propertyGridEditorDeleteRow'),
+                    $(rowItemTemplate)
+                ).on('click', function() {
+                    if ($(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'), $(editorHtml)).length > 1) {
+                        $(this)
+                            .closest(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'))
+                            .off()
+                            .empty()
+                            .remove();
+
+                        _setPropertyGridData(
+                            $(editorHtml),
+                            multiSelection,
+                            editorConfiguration['propertyPath'],
+                            propertyPathPrefix
+                        );
+                    } else {
+                        Notification.error(
+                            editorConfiguration['removeLastAvailableRowFlashMessageTitle'],
+                            editorConfiguration['removeLastAvailableRowFlashMessageMessage'],
+                            2
+                        );
+                    }
+                });
+            } else {
+                $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorDeleteRow'), $(rowItemTemplate))
+                    .parent()
+                    .off()
+                    .empty();
+            }
+
+            if (!!editorConfiguration['isSortable']) {
+                $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorContainer'), $(editorHtml))
+                    .addClass(getHelper().getDomElementClassName('sortable'))
+                    .sortable({
+                        revert: 'true',
+                        items: getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'),
+                        update: function(e, o) {
+                            _setPropertyGridData($(editorHtml), multiSelection, editorConfiguration['propertyPath'], propertyPathPrefix);
+                        }
+                    });
+            } else {
+                $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorSortRow'), $(rowItemTemplate))
+                    .parent()
+                    .off()
+                    .empty();
+            }
+
+            $(  getHelper().getDomElementDataIdentifierSelector('propertyGridEditorSelectValue'),
+                $(rowItemTemplate)
+            ).on('change', function() {
+                if (!multiSelection) {
+                    $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorSelectValue') + ':checked', $(editorHtml))
+                        .not($(this))
+                        .prop('checked', false);
+                }
+                _setPropertyGridData($(editorHtml), multiSelection, editorConfiguration['propertyPath'], propertyPathPrefix);
+            });
+
+            $(  getHelper().getDomElementDataIdentifierSelector('propertyGridEditorLabel') + ',' +
+                getHelper().getDomElementDataIdentifierSelector('propertyGridEditorValue'),
+                $(rowItemTemplate)
+            ).on('keyup paste', function() {
+                _setPropertyGridData($(editorHtml), multiSelection, editorConfiguration['propertyPath'], propertyPathPrefix);
+            });
+
+            $(  getHelper().getDomElementDataIdentifierSelector('propertyGridEditorLabel'),
+                $(rowItemTemplate)
+            ).on('focusout', function() {
+                if ('' === $(this)
+                                .closest(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'))
+                                .find(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorValue'))
+                                .val()
+                ) {
+                    $(this)
+                        .closest(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorRowItem'))
+                        .find(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorValue'))
+                        .val($(this).val());
+                }
+            });
+
+            if (!!editorConfiguration['enableAddRow']) {
+                addRowTemplate = $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorAddRowItem'), $(editorHtml)).clone();
+                $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorAddRowItem'), $(editorHtml)).remove();
+
+                $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorAddRow'), $(addRowTemplate)).on('click', function() {
+                    $(this)
+                        .closest(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorAddRowItem'))
+                        .before($(rowItemTemplate).clone(true, true));
+                });
+                $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorContainer'), $(editorHtml))
+                    .prepend($(addRowTemplate).clone(true, true));
+            } else {
+                $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorAddRowItem'), $(editorHtml)).remove();
+            }
+
+            defaultValue = {};
+            if (multiSelection) {
+                if (!getUtility().isUndefinedOrNull(getCurrentlySelectedFormElement().get(propertyPathPrefix + 'defaultValue'))) {
+                    defaultValue = getCurrentlySelectedFormElement().get(propertyPathPrefix + 'defaultValue');
+                }
+            } else {
+                if (!getUtility().isUndefinedOrNull(getCurrentlySelectedFormElement().get(propertyPathPrefix + 'defaultValue'))) {
+                    defaultValue = {0: getCurrentlySelectedFormElement().get(propertyPathPrefix + 'defaultValue')};
+                }
+            }
+            propertyData = getCurrentlySelectedFormElement().get(propertyPathPrefix + editorConfiguration['propertyPath']) || {};
+
+            setData = function(label, value) {
+                var isPreselected, newRowTemplate;
+
+                isPreselected = false;
+                newRowTemplate = $(rowItemTemplate).clone(true, true);
+
+                for (var defaultValueKey in defaultValue) {
+                    if (!defaultValue.hasOwnProperty(defaultValueKey)) {
+                        continue;
+                    }
+                    if (defaultValue[defaultValueKey] === value) {
+                        isPreselected = true;
+                        break;
+                    }
+                }
+
+                $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorLabel'), $(newRowTemplate)).val(label);
+                $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorValue'), $(newRowTemplate)).val(value);
+                if (isPreselected) {
+                    $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorSelectValue'), $(newRowTemplate))
+                        .prop('checked', true);
+                }
+
+                if (!!editorConfiguration['enableAddRow']) {
+                    $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorAddRowItem'), $(editorHtml))
+                        .before($(newRowTemplate));
+                } else {
+                    $(getHelper().getDomElementDataIdentifierSelector('propertyGridEditorContainer'), $(editorHtml))
+                        .prepend($(newRowTemplate));
+                }
+            };
+
+            if ('object' === $.type(propertyData)) {
+                for (var propertyDataKey in propertyData) {
+                    if (!propertyData.hasOwnProperty(propertyDataKey)) {
+                        continue;
+                    }
+                    setData(propertyData[propertyDataKey], propertyDataKey);
+                }
+            } else {
+                for (var i = 0, len = propertyData.length; i < len; ++i) {
+                    setData(propertyData[i]['_label'], propertyData[i]['_value']);
+                }
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param object editorConfiguration
+         * @param object editorHtml
+         * @param string collectionElementIdentifier
+         * @param string collectionName
+         * @return void
+         * @publish view/inspector/collectionElement/new/selected
+         * @publish view/inspector/removeCollectionElement/perform
+         * @throws 1475417093
+         * @throws 1475417094
+         * @throws 1475417095
+         * @throws 1475417096
+         */
+        function renderRequiredValidatorEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
+            var validatorIdentifier;
+            assert(
+                'object' === $.type(editorConfiguration),
+                'Invalid parameter "editorConfiguration"',
+                1475417093
+            );
+            assert(
+                'object' === $.type(editorHtml),
+                'Invalid parameter "editorHtml"',
+                1475417094
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['validatorIdentifier']),
+                'Invalid configuration "validatorIdentifier"',
+                1475417095
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['label']),
+                'Invalid configuration "label"',
+                1475417096
+            );
+
+            validatorIdentifier = editorConfiguration['validatorIdentifier'];
+            getHelper().getTemplatePropertyDomElement('label', editorHtml).append(editorConfiguration['label']);
+
+            if (-1 !== getFormEditorApp().getIndexFromPropertyCollectionElement(validatorIdentifier, 'validators')) {
+                $('input[type="checkbox"]', $(editorHtml)).prop('checked', true);
+            }
+
+            $('input[type="checkbox"]', $(editorHtml)).on('change', function() {
+                if ($(this).is(":checked")) {
+                    getPublisherSubscriber().publish(
+                        'view/inspector/collectionElement/new/selected',
+                        [validatorIdentifier, 'validators']
+                    );
+                } else {
+                    getPublisherSubscriber().publish(
+                        'view/inspector/removeCollectionElement/perform',
+                        [validatorIdentifier, 'validators']
+                    );                 
+                }
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @param object editorConfiguration
+         * @param object editorHtml
+         * @param string collectionElementIdentifier
+         * @param string collectionName
+         * @return void
+         * @throws 1476218671
+         * @throws 1476218672
+         * @throws 1476218673
+         * @throws 1476218674
+         */
+        function renderCheckboxEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
+            var propertyData, propertyPath;
+            assert(
+                'object' === $.type(editorConfiguration),
+                'Invalid parameter "editorConfiguration"',
+                1476218671
+            );
+            assert(
+                'object' === $.type(editorHtml),
+                'Invalid parameter "editorHtml"',
+                1476218672
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['label']),
+                'Invalid configuration "label"',
+                1476218673
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
+                'Invalid configuration "propertyPath"',
+                1476218674
+            );
+
+            getHelper()
+                .getTemplatePropertyDomElement('label', editorHtml)
+                .append(editorConfiguration['label']);
+
+            propertyPath = getFormEditorApp()
+                .buildPropertyPath(editorConfiguration['propertyPath'], collectionElementIdentifier, collectionName);
+            propertyData = getCurrentlySelectedFormElement().get(propertyPath);
+
+            if (
+                ('boolean' === $.type(propertyData) && propertyData)
+                || propertyData === 'true'
+                || propertyData === 1
+                || propertyData === "1"
+            ) {
+                $('input[type="checkbox"]', $(editorHtml)).prop('checked', true);
+            }
+
+            $('input[type="checkbox"]', $(editorHtml)).on('change', function() {
+                if ($(this).is(":checked")) {
+                    getCurrentlySelectedFormElement().set(propertyPath, true);
+                } else {
+                    getCurrentlySelectedFormElement().set(propertyPath, false);
+                }
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @param object editorConfiguration
+         * @param object editorHtml
+         * @param string collectionElementIdentifier
+         * @param string collectionName
+         * @return void
+         * @throws 1475412567
+         * @throws 1475412568
+         * @throws 1475416098
+         * @throws 1475416099
+         */
+        function renderTextareaEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
+            var propertyPath, propertyData;
+            assert(
+                'object' === $.type(editorConfiguration),
+                'Invalid parameter "editorConfiguration"',
+                1475412567
+            );
+            assert(
+                'object' === $.type(editorHtml),
+                'Invalid parameter "editorHtml"',
+                1475412568
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
+                'Invalid configuration "propertyPath"',
+                1475416098
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['label']),
+                'Invalid configuration "label"',
+                1475416099
+            );
+
+            propertyPath = getFormEditorApp()
+                .buildPropertyPath(editorConfiguration['propertyPath'], collectionElementIdentifier, collectionName);
+
+            getHelper()
+                .getTemplatePropertyDomElement('label', editorHtml).append(editorConfiguration['label']);
+
+            if (getUtility().isNonEmptyString(editorConfiguration['fieldExplanationText'])) {
+                getHelper()
+                    .getTemplatePropertyDomElement('fieldExplanationText', editorHtml)
+                    .text(editorConfiguration['fieldExplanationText']);
+            } else {
+                getHelper()
+                    .getTemplatePropertyDomElement('fieldExplanationText', editorHtml)
+                    .remove();
+            }
+
+            propertyData = getCurrentlySelectedFormElement().get(propertyPath);
+            $('textarea', $(editorHtml)).val(propertyData);
+
+            $('textarea', $(editorHtml)).on('keyup paste', function() {
+                getCurrentlySelectedFormElement().set(propertyPath, $(this).val());
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @param object editorConfiguration
+         * @param object editorHtml
+         * @param string collectionElementIdentifier
+         * @param string collectionName
+         * @return void
+         * @throws 1477300587
+         * @throws 1477300588
+         * @throws 1477300589
+         * @throws 1477300590
+         * @throws 1477318981
+         * @throws 1477319859
+         */
+        function renderTypo3WinBrowserEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
+            var iconType, propertyPath, propertyData;
+            assert(
+                'object' === $.type(editorConfiguration),
+                'Invalid parameter "editorConfiguration"',
+                1477300587
+            );
+            assert(
+                'object' === $.type(editorHtml),
+                'Invalid parameter "editorHtml"',
+                1477300588
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['label']),
+                'Invalid configuration "label"',
+                1477300589
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['buttonLabel']),
+                'Invalid configuration "buttonLabel"',
+                1477318981
+            );
+            assert(
+                getUtility().isNonEmptyString(editorConfiguration['propertyPath']),
+                'Invalid configuration "propertyPath"',
+                1477300590
+            );
+            assert(
+                'tt_content' === editorConfiguration['browsableType'] || 'pages' === editorConfiguration['browsableType'],
+                'Invalid configuration "browsableType"',
+                1477319859
+            );
+
+            getHelper()
+                .getTemplatePropertyDomElement('label', editorHtml)
+                .append(editorConfiguration['label']);
+            getHelper()
+                .getTemplatePropertyDomElement('buttonLabel', editorHtml)
+                .append(editorConfiguration['buttonLabel']);
+
+            if (getUtility().isNonEmptyString(editorConfiguration['fieldExplanationText'])) {
+                getHelper()
+                    .getTemplatePropertyDomElement('fieldExplanationText', editorHtml)
+                    .text(editorConfiguration['fieldExplanationText']);
+            } else {
+                getHelper()
+                    .getTemplatePropertyDomElement('fieldExplanationText', editorHtml)
+                    .remove();
+            }
+
+            $('form', $(editorHtml)).prop('name', editorConfiguration['propertyPath']);
+
+            iconType = ('tt_content' === editorConfiguration['browsableType'])
+                ? getHelper().getDomElementDataAttributeValue('iconTtContent')
+                : getHelper().getDomElementDataAttributeValue('iconPage');
+            Icons.getIcon(iconType, Icons.sizes.small).done(function(icon) {
+                getHelper().getTemplatePropertyDomElement('image', editorHtml).append($(icon));
+            });
+
+            getHelper().getTemplatePropertyDomElement('onclick', editorHtml).on('click', function() {
+                var insertTarget, randomIdentifier;
+
+                randomIdentifier = Math.floor((Math.random() * 100000) + 1);
+                insertTarget = $(this)
+                    .closest(getHelper().getDomElementDataIdentifierSelector('editorControlsWrapper'))
+                    .find(getHelper().getDomElementDataAttribute('contentElementSelectorTarget', 'bracesWithKey'));
+
+                insertTarget.attr(getHelper().getDomElementDataAttribute('contentElementSelectorTarget'), randomIdentifier);
+                _openTypo3WinBrowser('db', randomIdentifier + '|||' + editorConfiguration['browsableType']);
+            });
+
+            propertyPath = getFormEditorApp().buildPropertyPath(editorConfiguration['propertyPath'], collectionElementIdentifier, collectionName);
+            propertyData = getCurrentlySelectedFormElement().get(propertyPath);
+
+            _validateCollectionElement(propertyPath, editorHtml);
+            getHelper()
+                .getTemplatePropertyDomElement('propertyPath', editorHtml)
+                .val(propertyData);
+
+            getHelper().getTemplatePropertyDomElement('propertyPath', editorHtml).on('keyup paste', function() {
+                getCurrentlySelectedFormElement().set(propertyPath, $(this).val());
+                _validateCollectionElement(propertyPath, editorHtml);
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @param object editorConfiguration
+         * @param object editorHtml
+         * @param string collectionElementIdentifier
+         * @param string collectionName
+         * @return void
+         * @throws 1475412563
+         * @throws 1475412564
+         */
+        function renderRemoveElementEditor(editorConfiguration, editorHtml, collectionElementIdentifier, collectionName) {
+            assert('object' === $.type(editorConfiguration), 'Invalid parameter "editorConfiguration"', 1475412563);
+            assert('object' === $.type(editorHtml), 'Invalid parameter "editorHtml"', 1475412564);
+
+            if (getUtility().isUndefinedOrNull(collectionElementIdentifier)) {
+                
+                $('button', $(editorHtml))
+                    .addClass(
+                        getHelper().getDomElementClassName('buttonFormElementRemove') + ' ' +
+                        getHelper().getDomElementClassName('buttonFormEditor')
+                    );
+            } else {
+                $('button', $(editorHtml)).addClass(
+                    getHelper().getDomElementClassName('buttonCollectionElementRemove')
+                );
+            }
+
+            $('button', $(editorHtml)).on('click', function(e) {
+                if (getUtility().isUndefinedOrNull(collectionElementIdentifier)) {
+                    getViewModel().showRemoveFormElementModal();
+                } else {
+                    getViewModel().showRemoveCollectionElementModal(collectionElementIdentifier, collectionName);
+                }
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @param string content
+         * @return void
+         */
+        function setFormElementHeaderEditorContent(content) {
+            if (getFormEditorApp().getUtility().isUndefinedOrNull(content)) {
+                content = buildTitleByFormElement();
+            }
+
+            $(getHelper()
+                .getDomElementDataIdentifierSelector('formElementHeaderEditor'), getInspectorDomElement())
+                .html(content);
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return object
+         * @throws 1478967319
+         */
+        function buildTitleByFormElement(formElement) {
+            var label;
+            if (getUtility().isUndefinedOrNull(formElement)) {
+                formElement = getCurrentlySelectedFormElement();
+            }
+            assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1478967319);
+
+            return $('<span></span>').text((formElement.get('label')
+                ? formElement.get('label')
+                : formElement.get('identifier')));          
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param object
+         * @return this
+         */
+        function bootstrap(formEditorApp, configuration) {
+            _formEditorApp = formEditorApp;
+            _configuration = $.extend(true, _defaultConfiguration, configuration || {});
+            _helperSetup();
+            return this;
+        };
+
+        /**
+         * Publish the public methods.
+         * Implements the "Revealing Module Pattern".
+         */
+        return {
+            bootstrap: bootstrap,
+            buildTitleByFormElement: buildTitleByFormElement,
+            getCollectionElementDomElement: getCollectionElementDomElement,
+            getFinishersContainerDomElement: getFinishersContainerDomElement,
+            getInspectorDomElement: getInspectorDomElement,
+            getValidatorsContainerDomElement: getValidatorsContainerDomElement,
+            renderCheckboxEditor: renderCheckboxEditor,
+            renderCollectionElementEditors: renderCollectionElementEditors,
+            renderCollectionElementHeaderEditor: renderCollectionElementHeaderEditor,
+            renderCollectionElementSelectionEditor: renderCollectionElementSelectionEditor,
+            renderEditors: renderEditors,
+            renderFormElementHeaderEditor: renderFormElementHeaderEditor,
+            renderPropertyGridEditor: renderPropertyGridEditor,
+            renderRemoveElementEditor: renderRemoveElementEditor,
+            renderRequiredValidatorEditor: renderRequiredValidatorEditor,
+            renderSingleSelectEditor: renderSingleSelectEditor,
+            renderTextareaEditor: renderTextareaEditor,
+            renderTextEditor: renderTextEditor,
+            renderTypo3WinBrowserEditor: renderTypo3WinBrowserEditor,
+            setFormElementHeaderEditorContent: setFormElementHeaderEditorContent
+        };
+    })($, Helper, Icons, Notification);
+});
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/Mediator.js b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/Mediator.js
new file mode 100644
index 0000000000000000000000000000000000000000..475b0f2d8b8b93455f4da3c6cd23bb1dea6139a8
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/Mediator.js
@@ -0,0 +1,1059 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/Form/Backend/FormEditor/Mediator
+ */
+define(['jquery',
+        'TYPO3/CMS/Form/Backend/FormEditor/Helper'
+        ], function($, Helper) {
+        'use strict';
+
+    return (function($, Helper) {
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _formEditorApp = null;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _viewModel = null;
+
+        /* *************************************************************
+         * Private Methodes
+         * ************************************************************/
+
+        /**
+         * @private
+         *
+         * @return void
+         * @throws 1478268638
+         */
+        function _helperSetup() {
+            assert('function' === $.type(Helper.bootstrap),
+                'The view model helper does not implement the method "bootstrap"',
+                1478268638
+            );
+            Helper.bootstrap(getFormEditorApp());
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getFormEditorApp() {
+            return _formEditorApp;
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getViewModel() {
+            return _viewModel;
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getUtility() {
+            return getFormEditorApp().getUtility();
+        };
+
+        /**
+         * @private
+         *
+         * @param mixed test
+         * @param string message
+         * @param int messageCode
+         * @return void
+         */
+        function assert(test, message, messageCode) {
+            return getFormEditorApp().assert(test, message, messageCode);
+        };
+
+        /**
+         * @private
+         *
+         * @param object
+         * @return object
+         */
+        function getHelper(configuration) {
+            if (getUtility().isUndefinedOrNull(configuration)) {
+                return Helper.setConfiguration(getViewModel().getConfiguration());
+            }
+            return Helper.setConfiguration(configuration);
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getCurrentlySelectedFormElement() {
+            return getFormEditorApp().getCurrentlySelectedFormElement();
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getPublisherSubscriber() {
+            return getFormEditorApp().getPublisherSubscriber();
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getRootFormElement() {
+            return getFormEditorApp().getRootFormElement();
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         */
+        function _subscribeEvents() {
+
+            /* *********************************************************
+             * Misc
+             * ********************************************************/
+
+            /**
+             * @private
+             *
+             * @return string
+             */
+            window.onbeforeunload = function(e) {
+                if (!getFormEditorApp().getUnsavedContent()) {
+                    return;
+                }
+                e = e || window.event;
+                if (e) {
+                    e.returnValue = getFormEditorApp().getFormElementDefinition(getRootFormElement(), 'modalCloseDialogMessage');
+                }
+                return getFormEditorApp().getFormElementDefinition(getRootFormElement(), 'modalCloseDialogTitle');
+            };
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe view/ready
+             */
+            getPublisherSubscriber().subscribe('view/ready', function(topic, args) {
+                getViewModel().onViewReadyBatch();
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = applicationState
+             *              args[1] = stackPointer
+             *              args[2] = stackSize
+             * @return void
+             * @subscribe core/applicationState/add
+             */
+            getPublisherSubscriber().subscribe('core/applicationState/add', function(topic, args) {
+                getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderRedo')));
+                if (args[2] > 1 && args[1] <= args[2]) {
+                    getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderUndo')));
+                } else {
+                    getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderUndo')));
+                }
+            });
+
+            /* *********************************************************
+             * Ajax
+             * ********************************************************/
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = html
+             * @return void
+             * @subscribe core/ajax/saveFormDefinition/success
+             */
+            getPublisherSubscriber().subscribe('core/ajax/saveFormDefinition/success', function(topic, args) {
+                getFormEditorApp().setUnsavedContent(false);
+                getViewModel().showSaveSuccessMessage();
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = html
+             *              args[1] = pageIndex
+             * @return void
+             * @subscribe core/ajax/renderFormDefinitionPage/success
+             */
+            getPublisherSubscriber().subscribe('core/ajax/renderFormDefinitionPage/success', function(topic, args) {
+                getViewModel().renderPreviewStageArea(args[0]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = jqXHR
+             *              args[1] = textStatus
+             *              args[2] = errorThrown
+             * @return void
+             * @subscribe core/ajax/saveFormDefinition/error
+             */
+            getPublisherSubscriber().subscribe('core/ajax/error', function(topic, args) {
+                if (args[0].status !== 0) {
+                    getViewModel().showErrorFlashMessage(args[1], args[2]);
+                    getViewModel().renderPreviewStageArea(args[0].responseText);
+                }
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe ajax/beforeSend
+             */
+            getPublisherSubscriber().subscribe('ajax/beforeSend', function(topic, args) {
+                getViewModel().showSaveButtonSpinnerIcon();
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe ajax/complete
+             */
+            getPublisherSubscriber().subscribe('ajax/complete', function(topic, args) {
+                getViewModel().showSaveButtonSaveIcon();
+            });
+
+            /* *********************************************************
+             * Header
+             * ********************************************************/
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe view/header/button/save/clicked
+             */
+            getPublisherSubscriber().subscribe('view/header/button/save/clicked', function(topic, args) {
+
+                if (getFormEditorApp().validationResultsHasErrors(getFormEditorApp().validateFormElementRecursive(getRootFormElement(), true))) {
+                    getViewModel().showValidationErrorsModal();
+                } else {
+                    getFormEditorApp().saveFormDefinition();
+                }
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = targetEvent
+             * @return void
+             * @subscribe view/header/button/newPage/clicked
+             */
+            getPublisherSubscriber().subscribe('view/header/button/newPage/clicked', function(topic, args) {
+                if (getFormEditorApp().isRootFormElementSelected()) {
+                    getViewModel().selectPageBatch(0);
+                }
+                getViewModel().showInsertPagesModal(args[0]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe view/header/button/close/clicked
+             */
+            getPublisherSubscriber().subscribe('view/header/button/close/clicked', function(topic, args) {
+                getViewModel().showCloseConfirmationModal();
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe view/undoButton/clicked
+             */
+            getPublisherSubscriber().subscribe('view/undoButton/clicked', function(topic, args) {
+                getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderUndo')));
+                getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderRedo')));
+                getFormEditorApp().undoApplicationState();
+
+                if (getViewModel().getPreviewMode()) {
+                    getFormEditorApp().renderCurrentFormPage();
+                } else {
+                    getViewModel().renderAbstractStageArea();
+                }
+                getFormEditorApp().setUnsavedContent(true);
+
+                getViewModel().renewStructure();
+                getViewModel().renderPagination();
+                getViewModel().renderInspectorEditors();
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe view/redoButton/clicked
+             */
+            getPublisherSubscriber().subscribe('view/redoButton/clicked', function(topic, args) {
+                getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderUndo')));
+                getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderRedo')));
+                getFormEditorApp().redoApplicationState();
+
+                if (getViewModel().getPreviewMode()) {
+                    getFormEditorApp().renderCurrentFormPage();
+                } else {
+                    getViewModel().renderAbstractStageArea();
+                }
+                getFormEditorApp().setUnsavedContent(true);
+
+                getViewModel().renewStructure();
+                getViewModel().renderPagination();
+                getViewModel().renderInspectorEditors();
+            });
+
+            /* *********************************************************
+             * Stage
+             * ********************************************************/
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = formElementIdentifierPath
+             * @return void
+             * @subscribe view/stage/element/clicked
+             */
+            getPublisherSubscriber().subscribe('view/stage/element/clicked', function(topic, args) {
+                if (getCurrentlySelectedFormElement().get('__identifierPath') !== args[0]) {
+                    getFormEditorApp().setCurrentlySelectedFormElement(args[0]);
+                    getViewModel().renewStructure();
+                    getViewModel().refreshSelectedElementItemsBatch();
+                    getViewModel().addAbstractViewValidationResults();
+                    getViewModel().renderInspectorEditors();
+                }
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = targetEvent
+             * @return void
+             * @subscribe view/stage/abstract/elementToolbar/button/newElement/clicked
+             */
+            getPublisherSubscriber().subscribe('view/stage/abstract/elementToolbar/button/newElement/clicked', function(topic, args) {
+                if (getFormEditorApp().isRootFormElementSelected()) {
+                    getViewModel().selectPageBatch(0);
+                }
+                getViewModel().showInsertElementsModal(args[0]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = targetEvent
+             * @return void
+             * @subscribe view/newElementButton/clicked
+             */
+            getPublisherSubscriber().subscribe('view/stage/abstract/button/newElement/clicked', function(topic, args) {
+                if (getFormEditorApp().isRootFormElementSelected()) {
+                    getViewModel().selectPageBatch(0);
+                }
+                getViewModel().showInsertElementsModal(args[0]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = draggedFormElementDomElement
+             *              args[1] = draggedFormPlaceholderDomElement
+             * @return void
+             * @subscribe view/stage/abstract/dnd/start
+             */
+            getPublisherSubscriber().subscribe('view/stage/abstract/dnd/start', function(topic, args) {
+                getViewModel().onAbstractViewDndStartBatch(args[0], args[1]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = draggedFormElementIdentifierPath
+             * @return void
+             * @subscribe view/stage/abstract/dnd/stop
+             */
+            getPublisherSubscriber().subscribe('view/stage/abstract/dnd/stop', function(topic, args) {
+                getFormEditorApp().setCurrentlySelectedFormElement(args[0]);
+                getViewModel().renewStructure();
+                getViewModel().refreshSelectedElementItemsBatch();
+                getViewModel().addAbstractViewValidationResults();
+                getViewModel().renderInspectorEditors();
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = placeholderDomElement
+             *              args[1] = parentFormElementIdentifierPath
+             *              args[2] = enclosingCompositeFormElement
+             * @return void
+             * @subscribe view/stage/abstract/dnd/change
+             */
+            getPublisherSubscriber().subscribe('view/stage/abstract/dnd/change', function(topic, args) {
+                getViewModel().onAbstractViewDndChangeBatch(args[0], args[1], args[2]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = movedDomElement
+             *              args[1] = movedFormElementIdentifierPath
+             *              args[2] = previousFormElementIdentifierPath
+             *              args[3] = nextFormElementIdentifierPath
+             * @return void
+             * @subscribe view/stage/abstract/dnd/update
+             */
+            getPublisherSubscriber().subscribe('view/stage/abstract/dnd/update', function(topic, args) {
+                getViewModel().onAbstractViewDndUpdateBatch(args[0], args[1], args[2], args[3]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe view/viewModeButton/abstract/clicked
+             */
+            getPublisherSubscriber().subscribe('view/viewModeButton/abstract/clicked', function(topic, args) {
+                if (getViewModel().getPreviewMode()) {
+                    getViewModel().setPreviewMode(false);
+                    getViewModel().renderAbstractStageArea();
+                }
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe view/viewModeButton/preview/clicked
+             */
+            getPublisherSubscriber().subscribe('view/viewModeButton/preview/clicked', function(topic, args) {
+                if (!getViewModel().getPreviewMode()) {
+                    getViewModel().setPreviewMode(true);
+                    getFormEditorApp().renderCurrentFormPage();
+                }
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe view/paginationPrevious/clicked
+             */
+            getPublisherSubscriber().subscribe('view/paginationPrevious/clicked', function(topic, args) {
+                getViewModel().selectPageBatch(getFormEditorApp().getCurrentlySelectedPageIndex() - 1);
+                if (getViewModel().getPreviewMode()) {
+                    getFormEditorApp().renderCurrentFormPage();
+                } else {
+                    getViewModel().renderAbstractStageArea();
+                }
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe view/paginationNext/clicked
+             */
+            getPublisherSubscriber().subscribe('view/paginationNext/clicked', function(topic, args) {
+                getViewModel().selectPageBatch(getFormEditorApp().getCurrentlySelectedPageIndex() + 1);
+                if (getViewModel().getPreviewMode()) {
+                    getFormEditorApp().renderCurrentFormPage();
+                } else {
+                    getViewModel().renderAbstractStageArea();
+                }
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe view/stage/abstract/render/postProcess
+             */
+            getPublisherSubscriber().subscribe('view/stage/abstract/render/postProcess', function(topic, args) {
+                getViewModel().renderUndoRedo();
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe view/stage/preview/render/postProcess
+             */
+            getPublisherSubscriber().subscribe('view/stage/preview/render/postProcess', function(topic, args) {
+                getViewModel().renderUndoRedo();
+            });
+
+            /* *********************************************************
+             * Structure
+             * ********************************************************/
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = formElementIdentifierPath
+             * @return void
+             * @subscribe view/tree/node/clicked
+             */
+            getPublisherSubscriber().subscribe('view/tree/node/clicked', function(topic, args) {
+                var oldPageIndex;
+                if (getCurrentlySelectedFormElement().get('__identifierPath') !== args[0]) {
+                    oldPageIndex = getFormEditorApp().getCurrentlySelectedPageIndex();
+                    getFormEditorApp().setCurrentlySelectedFormElement(args[0]);
+                    if (oldPageIndex !== getFormEditorApp().getCurrentlySelectedPageIndex()) {
+                        getViewModel().renderAbstractStageArea();
+                    } else {
+                        getViewModel().renderAbstractStageArea(false);
+                    }
+                    getViewModel().renderPagination();
+                    getViewModel().renderInspectorEditors();
+                }
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe view/structure/root/selected
+             */
+            getPublisherSubscriber().subscribe('view/structure/root/selected', function(topic, args) {
+                if (!getFormEditorApp().isRootFormElementSelected()) {
+                    getViewModel().addStructureRootElementSelection();
+                    getFormEditorApp().setCurrentlySelectedFormElement(getRootFormElement());
+                    getViewModel().renderAbstractStageArea();
+                    getViewModel().renewStructure();
+                    getViewModel().renderPagination();
+                    getViewModel().renderInspectorEditors();
+                }
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = targetEvent
+             * @return void
+             * @subscribe view/header/button/newPage/clicked
+             */
+            getPublisherSubscriber().subscribe('view/structure/button/newPage/clicked', function(topic, args) {
+                if (getFormEditorApp().isRootFormElementSelected()) {
+                    getViewModel().selectPageBatch(0);
+                }
+                getViewModel().showInsertPagesModal(args[0]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = draggedFormElementIdentifierPath
+             * @return void
+             * @subscribe view/tree/dnd/stop
+             */
+            getPublisherSubscriber().subscribe('view/tree/dnd/stop', function(topic, args) {
+                getFormEditorApp().setCurrentlySelectedFormElement(args[0]);
+                getViewModel().renewStructure();
+                getViewModel().renderPagination();
+                getViewModel().renderAbstractStageArea();
+                getViewModel().renderInspectorEditors();
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = placeholderDomElement
+             *              args[1] = parentFormElementIdentifierPath
+             *              args[2] = enclosingCompositeFormElement
+             * @return void
+             * @subscribe view/tree/dnd/change
+             */
+            getPublisherSubscriber().subscribe('view/tree/dnd/change', function(topic, args) {
+                getViewModel().onStructureDndChangeBatch(args[0], args[1], args[2]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = movedDomElement
+             *              args[1] = movedFormElementIdentifierPath
+             *              args[2] = previousFormElementIdentifierPath
+             *              args[3] = nextFormElementIdentifierPath
+             * @return void
+             * @subscribe view/tree/dnd/update
+             */
+            getPublisherSubscriber().subscribe('view/tree/dnd/update', function(topic, args) {
+                getViewModel().onStructureDndUpdateBatch(args[0], args[1], args[2], args[3]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe view/structure/renew/postProcess
+             */
+            getPublisherSubscriber().subscribe('view/structure/renew/postProcess', function(topic, args) {
+                getViewModel().addStructureValidationResults();
+            });
+
+            /* *********************************************************
+             * Inspector
+             * ********************************************************/
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = collectionElementIdentifier
+             *              args[1] = collectionName
+             *              args[2] = formElement
+             * @return void
+             * @subscribe view/inspector/removeCollectionElement/perform
+             */
+            getPublisherSubscriber().subscribe('view/inspector/removeCollectionElement/perform', function(topic, args) {
+                getViewModel().removePropertyCollectionElement(args[0], args[1], args[2]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = collectionElementIdentifier
+             *              args[1] = collectionName
+             * @return void
+             * @subscribe view/inspector/collectionElement/selected
+             */
+            getPublisherSubscriber().subscribe('view/inspector/collectionElement/new/selected', function(topic, args) {
+                getViewModel().createAndAddPropertyCollectionElement(args[0], args[1]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = collectionElementIdentifier
+             *              args[1] = collectionName
+             * @return void
+             * @subscribe view/inspector/collectionElement/selected
+             */
+            getPublisherSubscriber().subscribe('view/inspector/collectionElement/existing/selected', function(topic, args) {
+                getViewModel().renderInspectorCollectionElementEditors(args[1], args[0]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = movedCollectionElementIdentifier
+             *              args[1] = previousCollectionElementIdentifier
+             *              args[2] = nextCollectionElementIdentifier
+             *              args[3] = collectionName
+             * @return void
+             * @subscribe view/inspector/collectionElements/dnd/update
+             * @throws 1477407673
+             */
+            getPublisherSubscriber().subscribe('view/inspector/collectionElements/dnd/update', function(topic, args) {
+                if (args[2]) {
+                    getViewModel().movePropertyCollectionElement(args[0], 'before', args[2], args[3]);
+                } else if (args[1]) {
+                    getViewModel().movePropertyCollectionElement(args[0], 'after', args[1], args[3]);
+                } else {
+                    assert(false, 'Next element or previous element need to be set.', 1477407673);
+                }
+            });
+
+            /* *********************************************************
+             * Form element
+             * ********************************************************/
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = propertyPath
+             *              args[1] = value
+             *              args[2] = oldValue
+             *              args[3] = formElementIdentifierPath
+             * @return void
+             * @subscribe core/formElement/somePropertyChanged
+             */
+            getPublisherSubscriber().subscribe('core/formElement/somePropertyChanged', function(topic, args) {
+                var hasError, validationElement, validationResults;
+
+                validationResults = [];
+                if ('renderables' !== args[0]) {
+                    if (!getFormEditorApp().isRootFormElementSelected() && 'label' === args[0]) {
+                        getViewModel().getStructure().setTreeNodeTitle();
+                        getViewModel().setInspectorFormElementHeaderEditorContent();
+                    } else if (!getFormEditorApp().getUtility().isUndefinedOrNull(args[3]) && getRootFormElement().get('__identifierPath') === args[3]) {
+                        getViewModel().setStructureRootElementTitle();
+                        getViewModel().setStageHeadline();
+                        getViewModel().setInspectorFormElementHeaderEditorContent();
+                    }
+
+                    if (getViewModel().getPreviewMode()) {
+                        getFormEditorApp().renderCurrentFormPage();
+                    } else {
+                        getViewModel().renderAbstractStageArea(false, false);
+                    }
+                    getViewModel().addStructureValidationResults();
+                }
+
+                getFormEditorApp().setUnsavedContent(true);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = parentFormElement
+             * @return void
+             * @subscribe view/formElement/removed
+             */
+            getPublisherSubscriber().subscribe('view/formElement/removed', function(topic, args) {
+                getFormEditorApp().setCurrentlySelectedFormElement(args[0]);
+                getViewModel().renewStructure();
+                getViewModel().renderAbstractStageArea();
+                getViewModel().renderPagination();
+                getViewModel().renderInspectorEditors();
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = newFormElement
+             * @return void
+             * @subscribe view/formElement/inserted
+             */
+            getPublisherSubscriber().subscribe('view/formElement/inserted', function(topic, args) {
+                getFormEditorApp().setCurrentlySelectedFormElement(args[0]);
+                getViewModel().renewStructure();
+                getViewModel().renderAbstractStageArea();
+                getViewModel().renderPagination();
+                getViewModel().renderInspectorEditors();
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = collectionElementIdentifier
+             *              args[1] = collectionName
+             *              args[2] = formElement
+             *              args[3] = collectionElementConfiguration
+             *              args[4] = referenceCollectionElementIdentifier
+             * @return void
+             * @subscribe view/collectionElement/new/added
+             */
+            getPublisherSubscriber().subscribe('view/collectionElement/new/added', function(topic, args) {
+                getViewModel().renderInspectorEditors();
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = movedCollectionElementIdentifier
+             *              args[1] = previousCollectionElementIdentifier
+             *              args[2] = nextCollectionElementIdentifier
+             *              args[3] = collectionName
+             * @return void
+             * @subscribe view/collectionElement/moved
+             * @throws 1477407673
+             */
+            getPublisherSubscriber().subscribe('view/collectionElement/moved', function(topic, args) {
+                getViewModel().renderInspectorEditors(undefined, false);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = collectionElementIdentifier
+             *              args[1] = collectionName
+             *              args[2] = formElement
+             * @return void
+             * @subscribe view/collectionElement/removed
+             */
+            getPublisherSubscriber().subscribe('view/collectionElement/removed', function(topic, args) {
+                getViewModel().renderInspectorEditors(undefined, false);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = formElementType
+             * @return void
+             * @subscribe view/insertElements/perform/bottom
+             */
+            getPublisherSubscriber().subscribe('view/insertElements/perform/bottom', function(topic, args) {
+                var lastRenderable;
+
+                lastRenderable = getFormEditorApp().getLastTopLevelElementOnCurrentPage();
+                if (!lastRenderable) {
+                    getViewModel().createAndAddFormElement(args[0], getFormEditorApp().getCurrentlySelectedPage());
+                } else {
+                    if (
+                        !getFormEditorApp().getFormElementDefinition(lastRenderable, '_isTopLevelFormElement')
+                        && getFormEditorApp().getFormElementDefinition(lastRenderable, '_isCompositeFormElement')
+                    ) {
+                        getViewModel().createAndAddFormElement(args[0], getFormEditorApp().getCurrentlySelectedPage());
+                    } else {
+                        getViewModel().createAndAddFormElement(args[0], lastRenderable);
+                    }
+                }
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = formElementType
+             * @return void
+             * @publish view/formElement/inserted
+             * @subscribe view/insertElements/perform/after
+             */
+            getPublisherSubscriber().subscribe('view/insertElements/perform/after', function(topic, args) {
+                var newFormElement;
+                newFormElement = getViewModel().createAndAddFormElement(args[0], undefined, true);
+                newFormElement = getViewModel().moveFormElement(newFormElement, 'after', getFormEditorApp().getCurrentlySelectedFormElement());
+                getPublisherSubscriber().publish('view/formElement/inserted', [newFormElement]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = formElementType
+             * @return void
+             * @subscribe view/insertElements/perform/inside
+             */
+            getPublisherSubscriber().subscribe('view/insertElements/perform/inside', function(topic, args) {
+                getViewModel().createAndAddFormElement(args[0]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = formElementType
+             * @return void
+             * @subscribe view/insertElements/perform/after
+             */
+            getPublisherSubscriber().subscribe('view/insertPages/perform', function(topic, args) {
+                getViewModel().createAndAddFormElement(args[0]);
+            });
+
+            /* *********************************************************
+             * Modals
+             * ********************************************************/
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             * @return void
+             * @subscribe view/modal/close/perform
+             */
+            getPublisherSubscriber().subscribe('view/modal/close/perform', function(topic, args) {
+                getFormEditorApp().setUnsavedContent(false);
+                getViewModel().closeEditor();
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = formElement
+             * @return void
+             * @subscribe view/modal/removeFormElement/perform
+             */
+            getPublisherSubscriber().subscribe('view/modal/removeFormElement/perform', function(topic, args) {
+                getViewModel().removeFormElement(args[0]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = collectionElementIdentifier
+             *              args[1] = collectionName
+             *              args[2] = formElement
+             * @return void
+             * @subscribe view/modal/removeCollectionElement/perform
+             */
+            getPublisherSubscriber().subscribe('view/modal/removeCollectionElement/perform', function(topic, args) {
+                getViewModel().removePropertyCollectionElement(args[0], args[1], args[2]);
+            });
+
+            /**
+             * @private
+             *
+             * @param string
+             * @param array
+             *              args[0] = formElementIdentifierPath
+             * @return void
+             * @subscribe view/modal/validationErrors/element/clicked
+             */
+            getPublisherSubscriber().subscribe('view/modal/validationErrors/element/clicked', function(topic, args) {
+                var oldPageIndex;
+                if (getCurrentlySelectedFormElement().get('__identifierPath') !== args[0]) {
+                    oldPageIndex = getFormEditorApp().getCurrentlySelectedPageIndex();
+                    getFormEditorApp().setCurrentlySelectedFormElement(args[0]);
+
+                    if (getViewModel().getPreviewMode()) {
+                        getViewModel().setPreviewMode(false);
+                    }
+
+                    if (oldPageIndex !== getFormEditorApp().getCurrentlySelectedPageIndex()) {
+                        getViewModel().renderAbstractStageArea();
+                    } else {
+                        getViewModel().renderAbstractStageArea(false);
+                    }
+
+                    getViewModel().renderPagination();
+                    getViewModel().renderInspectorEditors();
+                }
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param object
+         * @return void
+         */
+        function bootstrap(formEditorApp, viewModel) {
+            _formEditorApp = formEditorApp;
+            _viewModel = viewModel;
+            _helperSetup();
+            _subscribeEvents();
+        };
+
+        /**
+         * Implements the "Revealing Module Pattern".
+         */
+        return {
+            /**
+             * Publish the public methods.
+             */
+            bootstrap: bootstrap
+        };
+    })($, Helper);
+});
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/ModalsComponent.js b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/ModalsComponent.js
new file mode 100644
index 0000000000000000000000000000000000000000..7f81a37fd0d6dd0ba5673712bd5e4a6d92481d91
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/ModalsComponent.js
@@ -0,0 +1,493 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/Form/Backend/FormEditor/ModalsComponent
+ */
+define(['jquery',
+        'TYPO3/CMS/Form/Backend/FormEditor/Helper',
+        'TYPO3/CMS/Backend/Modal',
+        'TYPO3/CMS/Backend/Severity',
+        'TYPO3/CMS/Backend/Icons'
+        ], function($, Helper, Modal, Severity, Icons) {
+        'use strict';
+
+    return (function($, Helper, Modal, Severity, Icons) {
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _configuration = null;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _defaultConfiguration = {
+            domElementClassNames: {
+                buttonDefault: 'btn-default',
+                buttonInfo: 'btn-info',
+                buttonWarning: 'btn-warning'
+            },
+            domElementDataAttributeNames: {
+                elementType: 'element-type'
+            },
+            domElementDataAttributeValues: {
+                rowItem: 'rowItem',
+                rowLink: 'rowLink',
+                rowsContainer: 'rowsContainer',
+                templateInsertElements: 'Modal-InsertElements',
+                templateInsertPages: 'Modal-InsertPages',
+                templateValidationErrors: 'Modal-ValidationErrors'
+            }
+        };
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _formEditorApp = null;
+
+        /* *************************************************************
+         * Private Methodes
+         * ************************************************************/
+
+        /**
+         * @private
+         *
+         * @return void
+         * @throws 1478268638
+         */
+        function _helperSetup() {
+            assert('function' === $.type(Helper.bootstrap),
+                'The view model helper does not implement the method "bootstrap"',
+                1478268638
+            );
+            Helper.bootstrap(getFormEditorApp());
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getFormEditorApp() {
+            return _formEditorApp;
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return object
+         */
+        function getHelper(configuration) {
+            if (getUtility().isUndefinedOrNull(configuration)) {
+                return Helper.setConfiguration(_configuration);
+            }
+            return Helper.setConfiguration(configuration);
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getUtility() {
+            return getFormEditorApp().getUtility();
+        };
+
+        /**
+         * @private
+         *
+         * @param mixed test
+         * @param string message
+         * @param int messageCode
+         * @return void
+         */
+        function assert(test, message, messageCode) {
+            return getFormEditorApp().assert(test, message, messageCode);
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getRootFormElement() {
+            return getFormEditorApp().getRootFormElement();
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getPublisherSubscriber() {
+            return getFormEditorApp().getPublisherSubscriber();
+        };
+
+        /**
+         * @private
+         *
+         * @param object
+         * @param string
+         * @return mixed
+         */
+        function getFormElementDefinition(formElement, formElementDefinitionKey) {
+            return getFormEditorApp().getFormElementDefinition(formElement, formElementDefinitionKey);
+        };
+
+        /**
+         * @public
+         *
+         * @param string publisherTopicName
+         * @param object publisherTopicArguments
+         * @return void
+         * @throws 1478889044
+         * @throws 1478889049
+         */
+        function _showRemoveElementModal(publisherTopicName, publisherTopicArguments) {
+            var modalButtons = [];
+
+            assert(
+                getUtility().isNonEmptyString(publisherTopicName),
+                'Invalid parameter "publisherTopicName"',
+                1478889049
+            );
+            assert(
+                'array' === $.type(publisherTopicArguments),
+                'Invalid parameter "formElement"',
+                1478889044
+            );
+
+            modalButtons.push({
+                text: getFormElementDefinition(getRootFormElement(), 'modalRemoveElementCancleButton'),
+                active: true,
+                btnClass: getHelper().getDomElementClassName('buttonDefault'),
+                name: 'cancel',
+                trigger: function () {
+                    Modal.currentModal.trigger('modal-dismiss');
+                }
+            });
+
+            modalButtons.push({
+                text: getFormElementDefinition(getRootFormElement(), 'modalRemoveElementConfirmButton'),
+                active: true,
+                btnClass: getHelper().getDomElementClassName('buttonWarning'),
+                name: 'confirm',
+                trigger: function () {
+                    getPublisherSubscriber().publish(publisherTopicName, publisherTopicArguments);
+                    Modal.currentModal.trigger('modal-dismiss');
+                }
+            });
+
+            Modal.show(
+                getFormElementDefinition(getRootFormElement(), 'modalRemoveElementDialogTitle'),
+                getFormElementDefinition(getRootFormElement(), 'modalRemoveElementDialogMessage'),
+                Severity.warning,
+                modalButtons
+            );
+        };
+
+        /**
+         * @private
+         *
+         * @param object modalContent
+         * @param string publisherTopicName
+         * @return void
+         * @publish mixed
+         * @throws 1478910954
+         */
+        function _insertElementsModalSetup(modalContent, publisherTopicName) {
+            assert(
+                getUtility().isNonEmptyString(publisherTopicName),
+                'Invalid parameter "publisherTopicName"',
+                1478910954
+            );
+
+            $('a', modalContent).on("click", function(e) {
+                getPublisherSubscriber().publish(publisherTopicName, [$(this).data(getHelper().getDomElementDataAttribute('elementType'))]);
+                $('a', modalContent).off();
+                Modal.currentModal.trigger('modal-dismiss');
+            });
+        };
+
+        /**
+         * @private
+         *
+         * @param object modalContent
+         * @param object validationResults
+         * @return void
+         * @publish view/modal/validationErrors/element/clicked
+         * @throws 1479161268
+         */
+        function _validationErrorsModalSetup(modalContent, validationResults) {
+            var formElement, newRowItem, rowItemTemplate;
+
+            assert(
+                'array' === $.type(validationResults),
+                'Invalid parameter "validationResults"',
+                1479161268
+            );
+
+            rowItemTemplate = $(
+                getHelper().getDomElementDataIdentifierSelector('rowItem'),
+                modalContent
+            ).clone();
+
+            $(getHelper().getDomElementDataIdentifierSelector('rowItem'), modalContent).remove();
+
+            for (var i = 0, len = validationResults.length; i < len; ++i) {
+                var hasError = false, validationElement;
+                for (var j = 0, len2 = validationResults[i]['validationResults'].length; j < len2; ++j) {
+                    if (
+                        validationResults[i]['validationResults'][j]['validationResults']
+                        && validationResults[i]['validationResults'][j]['validationResults'].length > 0
+                    ) {
+                        hasError = true;
+                        break;
+                    }
+                }
+
+                if (hasError) {
+                    formElement = getFormEditorApp()
+                        .getFormElementByIdentifierPath(validationResults[i]['formElementIdentifierPath']);
+                    newRowItem = rowItemTemplate.clone();
+                    $(getHelper().getDomElementDataIdentifierSelector('rowLink'), newRowItem)
+                        .attr(
+                            getHelper().getDomElementDataAttribute('elementIdentifier'),
+                            validationResults[i]['formElementIdentifierPath']
+                        )
+                        .html(_buildTitleByFormElement(formElement));
+                    $(getHelper().getDomElementDataIdentifierSelector('rowsContainer'), modalContent)
+                        .append(newRowItem);
+                }
+            }
+
+            $('a', modalContent).on("click", function(e) {
+                getPublisherSubscriber().publish('view/modal/validationErrors/element/clicked', [
+                    $(this).attr(getHelper().getDomElementDataAttribute('elementIdentifier'))
+                ]);
+                $('a', modalContent).off();
+                Modal.currentModal.trigger('modal-dismiss');
+            });
+        };
+
+        /**
+         * @private
+         *
+         * @param object
+         * @return object
+         * @throws 1479162557
+         */
+        function _buildTitleByFormElement(formElement) {
+            var label;
+            assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1479162557);
+
+            return $('<span></span>').text((formElement.get('label')
+                ? formElement.get('label')
+                : formElement.get('identifier')));          
+        };
+
+        /* *************************************************************
+         * Public Methodes
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @param object formElement
+         * @return void
+         * @publish view/modal/removeFormElement/perform
+         */
+        function showRemoveFormElementModal(formElement) {
+            _showRemoveElementModal('view/modal/removeFormElement/perform', [formElement]);
+        };
+
+        /**
+         * @public
+         *
+         * @param string collectionElementIdentifier
+         * @param string collectionName
+         * @param object formElement
+         * @return void
+         * @publish view/modal/removeCollectionElement/perform
+         * @throws 1478894420
+         * @throws 1478894421
+         */
+        function showRemoveCollectionElementModal(collectionElementIdentifier, collectionName, formElement) {
+            assert(
+                getUtility().isNonEmptyString(collectionElementIdentifier),
+                'Invalid parameter "collectionElementIdentifier"',
+                1478894420
+            );
+            assert(
+                getUtility().isNonEmptyString(collectionName),
+                'Invalid parameter "collectionName"',
+                1478894421
+            );
+
+            _showRemoveElementModal('view/modal/removeCollectionElement/perform', [collectionElementIdentifier, collectionName, formElement]);
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         * @publish view/modal/close/perform
+         */
+        function showCloseConfirmationModal() {
+            var  modalButtons = [];
+
+            modalButtons.push({
+                text: getFormElementDefinition(getRootFormElement(), 'modalCloseCancleButton'),
+                active: true,
+                btnClass: getHelper().getDomElementClassName('buttonDefault'),
+                name: 'cancel',
+                trigger: function () {
+                    Modal.currentModal.trigger('modal-dismiss');
+                }
+            });
+
+            modalButtons.push({
+                text: getFormElementDefinition(getRootFormElement(), 'modalCloseConfirmButton'),
+                active: true,
+                btnClass: getHelper().getDomElementClassName('buttonWarning'),
+                name: 'confirm',
+                trigger: function () {
+                    getPublisherSubscriber().publish('view/modal/close/perform', []);
+                    Modal.currentModal.trigger('modal-dismiss');
+                }
+            });
+
+            Modal.show(
+                getFormElementDefinition(getRootFormElement(), 'modalCloseDialogTitle'),
+                getFormElementDefinition(getRootFormElement(), 'modalCloseDialogMessage'),
+                Severity.warning,
+                modalButtons
+            );
+        };
+
+        /**
+         * @public
+         *
+         * @param string
+         * @param string
+         * @return void
+         */
+        function showInsertElementsModal(publisherTopicName) {
+            var html, template;
+
+            template = getHelper().getTemplate('templateInsertElements');
+            if (template.length > 0) {
+                html = $(template.html());
+                _insertElementsModalSetup(html, publisherTopicName);
+
+                Modal.show(
+                    getFormElementDefinition(getRootFormElement(), 'modalInsertElementsDialogTitle'),
+                    $(html),
+                    Severity.info
+                );
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param string
+         * @param string
+         * @return void
+         */
+        function showInsertPagesModal(publisherTopicName) {
+            var html, template;
+
+            template = getHelper().getTemplate('templateInsertPages');
+            if (template.length > 0) {
+                html = $(template.html());
+                _insertElementsModalSetup(html, publisherTopicName);
+
+                Modal.show(
+                    getFormElementDefinition(getRootFormElement(), 'modalInsertPagesDialogTitle'),
+                    $(html),
+                    Severity.info
+                );
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return void
+         */
+        function showValidationErrorsModal(validationResults) {
+            var html, template, modalButtons = [];
+
+            modalButtons.push({
+                text: getFormElementDefinition(getRootFormElement(), 'modalValidationErrorsConfirmButton'),
+                active: true,
+                btnClass: getHelper().getDomElementClassName('buttonDefault'),
+                name: 'confirm',
+                trigger: function () {
+                    Modal.currentModal.trigger('modal-dismiss');
+                }
+            });
+
+            template = getHelper().getTemplate('templateValidationErrors');
+            if (template.length > 0) {
+                html = $(template.html()).clone();
+                _validationErrorsModalSetup(html, validationResults);
+
+                Modal.show(
+                    getFormElementDefinition(getRootFormElement(), 'modalValidationErrorsDialogTitle'),
+                    html,
+                    Severity.error,
+                    modalButtons
+                );
+            }
+        }
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param object
+         * @return this
+         */
+        function bootstrap(formEditorApp, configuration) {
+            _formEditorApp = formEditorApp;
+            _configuration = $.extend(true, _defaultConfiguration, configuration || {});
+            _helperSetup();
+            return this;
+        };
+
+        /**
+         * Publish the public methods.
+         * Implements the "Revealing Module Pattern".
+         */
+        return {
+            bootstrap: bootstrap,
+            showCloseConfirmationModal: showCloseConfirmationModal,
+            showInsertElementsModal: showInsertElementsModal,
+            showInsertPagesModal: showInsertPagesModal,
+            showRemoveCollectionElementModal: showRemoveCollectionElementModal,
+            showRemoveFormElementModal: showRemoveFormElementModal,
+            showValidationErrorsModal: showValidationErrorsModal
+        };
+    })($, Helper, Modal, Severity, Icons);
+});
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/StageComponent.js b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/StageComponent.js
new file mode 100644
index 0000000000000000000000000000000000000000..f69b522f65ea16d17b6fd77756fa5a71dfd30327
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/StageComponent.js
@@ -0,0 +1,1119 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/Form/Backend/FormEditor/StageComponent
+ */
+define(['jquery',
+        'TYPO3/CMS/Form/Backend/FormEditor/Helper',
+        'TYPO3/CMS/Backend/Icons',
+        'TYPO3/CMS/Form/Backend/Vendor/jquery.mjs.nestedSortable'
+        ], function($, Helper, Icons) {
+        'use strict';
+
+    return (function($, Helper, Icons) {
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _configuration = null;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _defaultConfiguration = {
+            domElementClassNames: {
+                formElementIsComposit: 't3-form-element-composit',
+                formElementIsTopLevel: 't3-form-element-toplevel',
+                noNesting: 'mjs-nestedSortable-no-nesting',
+                selected: 'selected',
+                sortable: 'sortable',
+                previewViewPreviewElement: 't3-form-element-preview'
+            },
+            domElementDataAttributeNames: {
+                abstractType: 'data-element-abstract-type',
+                noSorting: 'data-no-sorting'
+            },
+            domElementDataAttributeValues: {
+                abstractViewToolbar: 'elementToolbar',
+                abstractViewToolbarNewElement: 'stageElementToolbarNewElement',
+                abstractViewToolbarNewElementSplitButton: 'stageElementToolbarNewElementSplitButton',
+                abstractViewToolbarNewElementSplitButtonAfter: 'stageElementToolbarNewElementSplitButtonAfter',
+                abstractViewToolbarNewElementSplitButtonInside: 'stageElementToolbarNewElementSplitButtonInside',
+                abstractViewToolbarRemoveElement: 'stageElementToolbarRemoveElement',
+                buttonHeaderRedo: 'redoButton',
+                buttonHeaderUndo: 'undoButton',
+                buttonPaginationPrevious: 'buttonPaginationPrevious',
+                buttonPaginationNext: 'buttonPaginationNext',
+                'FormElement-_ElementToolbar': 'FormElement-_ElementToolbar',
+                'FormElement-_UnknownElement': 'FormElement-_UnknownElement',
+                'FormElement-AdvancedPassword': 'FormElement-AdvancedPassword',
+                'FormElement-Checkbox': 'FormElement-Checkbox',
+                'FormElement-ContentElement': 'FormElement-ContentElement',
+                'FormElement-DatePicker': 'FormElement-DatePicker',
+                'FormElement-Fieldset': 'FormElement-Fieldset',
+                'FormElement-FileUpload': 'FormElement-FileUpload',
+                'FormElement-Hidden': 'FormElement-Hidden',
+                'FormElement-ImageUpload': 'FormElement-ImageUpload',
+                'FormElement-MultiCheckbox': 'FormElement-MultiCheckbox',
+                'FormElement-MultiSelect': 'FormElement-MultiSelect',
+                'FormElement-Page': 'FormElement-Page',
+                'FormElement-Password': 'FormElement-Password',
+                'FormElement-RadioButton': 'FormElement-RadioButton',
+                'FormElement-SingleSelect': 'FormElement-SingleSelect',
+                'FormElement-StaticText': 'FormElement-StaticText',
+                'FormElement-SummaryPage': 'FormElement-SummaryPage',
+                'FormElement-Text': 'FormElement-Text',
+                'FormElement-Textarea': 'FormElement-Textarea',
+                formElementIcon: 'elementIcon',
+                iconValidator: 't3-form-icon-validator',
+                multiValueContainer: 'multiValueContainer',
+                paginationTitle: 'paginationTitle',
+                stageHeadline: 'formDefinitionLabel',
+                stagePanel: 'stagePanel',
+                validatorsContainer: 'validatorsContainer',
+                validatorIcon: 'validatorIcon'
+            },
+            isSortable: true
+        };
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _formEditorApp = null;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _stageDomElement = null;
+
+        /* *************************************************************
+         * Private Methodes
+         * ************************************************************/
+
+        /**
+         * @private
+         *
+         * @return void
+         * @throws 1478268638
+         */
+        function _helperSetup() {
+            assert('function' === $.type(Helper.bootstrap),
+                'The view model helper does not implement the method "bootstrap"',
+                1478268638
+            );
+            Helper.bootstrap(getFormEditorApp());
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getFormEditorApp() {
+            return _formEditorApp;
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return object
+         */
+        function getHelper(configuration) {
+            if (getUtility().isUndefinedOrNull(configuration)) {
+                return Helper.setConfiguration(_configuration);
+            }
+            return Helper.setConfiguration(configuration);
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getUtility() {
+            return getFormEditorApp().getUtility();
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getViewModel() {
+            return getFormEditorApp().getViewModel();
+        };
+
+        /**
+         * @private
+         *
+         * @param mixed test
+         * @param string message
+         * @param int messageCode
+         * @return void
+         */
+        function assert(test, message, messageCode) {
+            return getFormEditorApp().assert(test, message, messageCode);
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getRootFormElement() {
+            return getFormEditorApp().getRootFormElement();
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getCurrentlySelectedFormElement() {
+            return getFormEditorApp().getCurrentlySelectedFormElement();
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getPublisherSubscriber() {
+            return getFormEditorApp().getPublisherSubscriber();
+        };
+
+        /**
+         * @private
+         *
+         * @param object
+         * @param string
+         * @return mixed
+         */
+        function getFormElementDefinition(formElement, formElementDefinitionKey) {
+            return getFormEditorApp().getFormElementDefinition(formElement, formElementDefinitionKey);
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         * @return string
+         * @return void
+         */
+        function _setTemplateTextContent(domElement, content) {
+            if (getUtility().isNonEmptyString(content)) {
+                $(domElement).text(content);
+            }
+        }
+
+        /**
+         * @private
+         *
+         * @param object
+         * @param object
+         * @return void
+         * @publish view/stage/abstract/render/template/perform
+         */
+        function _renderTemplateDispatcher(formElement, template) {
+            switch (formElement.get('type')) {
+                case 'Checkbox':
+                    renderCheckboxTemplate(formElement, template);
+                    break;
+                case 'FileUpload':
+                case 'ImageUpload':
+                    renderFileUploadTemplates(formElement, template);
+                    break;
+                case 'SingleSelect':
+                case 'RadioButton':
+                case 'MultiSelect':
+                case 'MultiCheckbox':
+                    renderSelectTemplates(formElement, template);
+                    break;
+                case 'Textarea':
+                case 'AdvancedPassword':
+                case 'Password':
+                case 'Text':
+                    renderSimpleTemplateWithValidators(formElement, template);
+                    break;
+                case 'Fieldset':
+                case 'SummaryPage':
+                case 'Page':
+                case 'DatePicker':
+                case 'StaticText':
+                case 'Hidden':
+                case 'ContentElement':
+                    renderSimpleTemplate(formElement, template);
+                    break;
+            }
+            getPublisherSubscriber().publish('view/stage/abstract/render/template/perform', [formElement, template]);
+        };
+
+        /**
+         * @private
+         *
+         * @param object
+         * @return object
+         * @throws 1478987818
+         */
+        function _renderNestedSortableListItem(formElement) {
+            var childFormElements, childList, listItem, template;
+
+            listItem = $('<li></li>');
+            if (!getFormElementDefinition(formElement, '_isCompositeFormElement')) {
+                listItem.addClass(getHelper().getDomElementClassName('noNesting'));
+            }
+
+            if (getFormElementDefinition(formElement, '_isTopLevelFormElement')) {
+                listItem.addClass(getHelper().getDomElementClassName('formElementIsTopLevel'));
+            }
+            if (getFormElementDefinition(formElement, '_isCompositeFormElement')) {
+                listItem.addClass(getHelper().getDomElementClassName('formElementIsComposit'));
+            }
+
+            try {
+                template = getHelper().getTemplate('FormElement-' + formElement.get('type')).clone();
+            } catch(error) {
+                template = getHelper().getTemplate('FormElement-_UnknownElement').clone();
+                assert(
+                    template.length,
+                    'No template found for element "' + formElement.get('__identifierPath') + '"',
+                    1478987818
+                );
+            }
+
+            template = $('<div></div>')
+                .attr(getHelper().getDomElementDataAttribute('elementIdentifier'), formElement.get('__identifierPath'))
+                .append($(template.html()));
+
+            if (getFormElementDefinition(formElement, '_isCompositeFormElement')) {
+                template.attr(getHelper().getDomElementDataAttribute('abstractType'), 'isCompositeFormElement');
+            }
+            if (getFormElementDefinition(formElement, '_isTopLevelFormElement')) {
+                template.attr(getHelper().getDomElementDataAttribute('abstractType'), 'isTopLevelFormElement');
+            }
+            listItem.append(template);
+
+            _renderTemplateDispatcher(formElement, template);
+
+            childFormElements = formElement.get('renderables');
+            childList = null;
+            if ('array' === $.type(childFormElements)) {
+                childList = $('<ol></ol>');
+                if (getFormElementDefinition(formElement, '_isTopLevelFormElement')) {
+                    childList.addClass(getHelper().getDomElementClassName('sortable'));
+                }
+                for (var i = 0, len = childFormElements.length; i < len; ++i) {
+                    childList.append(_renderNestedSortableListItem(childFormElements[i]));
+                }
+            }
+
+            if (childList) {
+                listItem.append(childList);
+            }
+            return listItem;
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         * @publish view/stage/abstract/dnd/start
+         * @publish view/stage/abstract/dnd/stop
+         * @publish view/stage/abstract/dnd/change
+         * @publish view/stage/abstract/dnd/update
+         */
+        function _addSortableEvents() {
+            $('ol.' + getHelper().getDomElementClassName('sortable'), _stageDomElement).nestedSortable({
+                forcePlaceholderSize: true,
+                handle: 'div'  + getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey'),
+                helper:	'clone',
+                items: 'li:not(' + getHelper().getDomElementDataAttribute('noSorting', 'bracesWithKey') + ')',
+                opacity: .6,
+                revert: 250,
+                delay: 200,
+                tolerance: 'pointer',
+                toleranceElement: '> div',
+
+                start: function(e, o) {
+                    getPublisherSubscriber().publish('view/stage/abstract/dnd/start', [$(o.item), $(o.placeholder)]);
+                },
+                stop: function(e, o) {
+                    getPublisherSubscriber().publish('view/stage/abstract/dnd/stop', [
+                        getAbstractViewFormElementIdentifierPathWithinDomElement($(o.item))
+                    ]);
+                },
+                change: function(e, o) {
+                    var enclosingCompositeFormElement, parentFormElementIdentifierPath;
+
+                    parentFormElementIdentifierPath = getAbstractViewParentFormElementIdentifierPathWithinDomElement($(o.placeholder));
+                    if (parentFormElementIdentifierPath) {
+                        enclosingCompositeFormElement = getFormEditorApp()
+                            .findEnclosingCompositeFormElementWhichIsNotOnTopLevel(parentFormElementIdentifierPath);
+                    }
+                    getPublisherSubscriber().publish('view/stage/abstract/dnd/change', [
+                        $(o.placeholder),
+                        parentFormElementIdentifierPath, enclosingCompositeFormElement
+                    ]);
+                },
+                update: function(e, o) {
+                    var nextFormElementIdentifierPath, movedFormElement, movedFormElementIdentifierPath, parentFormElementIdentifierPath, previousFormElementIdentifierPath;
+
+                    movedFormElementIdentifierPath = getAbstractViewFormElementIdentifierPathWithinDomElement($(o.item));
+                    previousFormElementIdentifierPath = getAbstractViewSiblingFormElementIdentifierPathWithinDomElement($(o.item), 'prev');
+                    nextFormElementIdentifierPath = getAbstractViewSiblingFormElementIdentifierPathWithinDomElement($(o.item), 'next');
+
+                    getPublisherSubscriber().publish('view/stage/abstract/dnd/update', [
+                        $(o.item),
+                        movedFormElementIdentifierPath,
+                        previousFormElementIdentifierPath,
+                        nextFormElementIdentifierPath
+                    ]);
+                }
+            });
+        };
+
+        /* *************************************************************
+         * Public Methodes
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function getStageDomElement() {
+            return _stageDomElement;
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return object
+         * @throws 1479037151
+         */
+        function buildTitleByFormElement(formElement) {
+            if (getUtility().isUndefinedOrNull(formElement)) {
+                formElement = getRootFormElement();
+            }
+            assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1479037151);
+
+            return $('<span></span>')
+                .text((formElement.get('label') ? formElement.get('label') : formElement.get('identifier')));
+        };
+
+        /**
+         * @public
+         *
+         * @param string title
+         * @return void
+         */
+        function setStageHeadline(title) {
+            if (getUtility().isUndefinedOrNull(title)) {
+                title = buildTitleByFormElement();
+            }
+
+            $(getHelper().getDomElementDataIdentifierSelector('stageHeadline')).html(title);
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function getStagePanelDomElement() {
+            return $(getHelper().getDomElementDataIdentifierSelector('stagePanel'));
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function renderPagination() {
+            var pageCount;
+
+            pageCount = getRootFormElement().get('renderables').length;
+
+            getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector('buttonPaginationPrevious')));
+            getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector('buttonPaginationNext')));
+
+            if (getFormEditorApp().getCurrentlySelectedPageIndex() === 0) {
+                getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonPaginationPrevious')));
+            }
+
+            if (pageCount === 1 || getFormEditorApp().getCurrentlySelectedPageIndex() === (pageCount - 1)) {
+                getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonPaginationNext')));
+            }
+
+            $(getHelper().getDomElementDataIdentifierSelector('paginationTitle')).text(
+                getFormElementDefinition(getRootFormElement(), 'paginationTitle')
+                    .replace('{0}', getFormEditorApp().getCurrentlySelectedPageIndex() + 1)
+                    .replace('{1}', pageCount)
+            );
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function renderUndoRedo() {
+            getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderUndo')));
+            getViewModel().enableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderRedo')));
+
+            if (getFormEditorApp().getCurrentApplicationStatePosition() + 1 >= getFormEditorApp().getCurrentApplicationStates()) {
+                getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderUndo')));
+            }
+            if (getFormEditorApp().getCurrentApplicationStatePosition() === 0) {
+                getViewModel().disableButton($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderRedo')));
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return string
+         */
+        function getAllFormElementDomElements() {
+            return $(   getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey'),
+                        _stageDomElement
+                    );
+        };
+
+        /* *************************************************************
+         * Abstract stage
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @param int
+         * @return object
+         * @throws 1478721208
+         */
+        function renderFormDefinitionPageAsSortableList(pageIndex) {
+            assert(
+                'number' === $.type(pageIndex),
+                'Invalid parameter "pageIndex"',
+                1478721208
+            );
+
+            return $('<ol></ol>')
+                .append(_renderNestedSortableListItem(getRootFormElement().get('renderables')[pageIndex]));
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return string
+         */
+        function getAbstractViewParentFormElementWithinDomElement(element) {
+            return $(element)
+                .parent()
+                .closest('li')
+                .find(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey'))
+                .first();
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return string
+         */
+        function getAbstractViewParentFormElementIdentifierPathWithinDomElement(element) {
+            return getAbstractViewParentFormElementWithinDomElement(element)
+                .attr(getHelper().getDomElementDataAttribute('elementIdentifier'));
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return string
+         */
+        function getAbstractViewFormElementWithinDomElement(element) {
+            return $(element)
+                .find(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey'))
+                .first();
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return string
+         */
+        function getAbstractViewFormElementIdentifierPathWithinDomElement(element) {
+            return getAbstractViewFormElementWithinDomElement($(element))
+                .attr(getHelper().getDomElementDataAttribute('elementIdentifier'));
+        };
+
+        /**
+         * @private
+         *
+         * @param object
+         * @param string
+         * @return string
+         */
+        function getAbstractViewSiblingFormElementIdentifierPathWithinDomElement(element, position) {
+            var formElementIdentifierPath;
+
+            if (getUtility().isUndefinedOrNull(position)) {
+                position = 'prev';
+            }
+            formElementIdentifierPath = getAbstractViewFormElementIdentifierPathWithinDomElement(element);
+            element = (position === 'prev') ? $(element).prev('li') : $(element).next('li');
+            return element.find(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey'))
+                .not(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKeyValue', [formElementIdentifierPath]))
+                .first()
+                .attr(getHelper().getDomElementDataAttribute('elementIdentifier'));
+        };
+
+        /**
+         * @public
+         *
+         * @param string|object
+         * @return object
+         */
+        function getAbstractViewFormElementDomElement(formElement) {
+            var formElementIdentifierPath;
+
+            if ('string' === $.type(formElement)) {
+                formElementIdentifierPath = formElement;
+            } else {
+                if (getUtility().isUndefinedOrNull(formElement)) {
+                    formElementIdentifierPath = getCurrentlySelectedFormElement().get('__identifierPath');
+                } else {
+                    formElementIdentifierPath = formElement.get('__identifierPath');
+                }
+            }
+            return $(getHelper()
+                .getDomElementDataAttribute('elementIdentifier', 'bracesWithKeyValue', [formElementIdentifierPath]), _stageDomElement);
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function removeAllStageToolbars() {
+            $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbar'), _stageDomElement).off().empty().remove();
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return object
+         * @publish view/insertElements/perform/after
+         * @publish view/insertElements/perform/inside
+         * @throws 1479035778
+         */
+        function createAbstractViewFormElementToolbar(formElement) {
+            var formElementTypeDefinition, template;
+            assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1479035778);
+
+            formElementTypeDefinition = getFormElementDefinition(formElement);
+            if (formElementTypeDefinition['_isTopLevelFormElement']) {
+                return $();
+            }
+
+            template = getHelper().getTemplate('FormElement-_ElementToolbar').clone();
+            if (!template.length) {
+                return $();
+            }
+
+            template = $($(template.html()));
+
+            getHelper().getTemplatePropertyDomElement('_type', template).text(formElement.get('type'));
+            getHelper().getTemplatePropertyDomElement('_identifier', template).text(formElement.get('identifier'));
+
+            if (formElementTypeDefinition['_isCompositeFormElement']) {
+                getViewModel().hideComponent($(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElement'), template));
+
+                $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElementSplitButtonAfter'), template).on('click', function(e) {
+                    getPublisherSubscriber().publish('view/stage/abstract/elementToolbar/button/newElement/clicked', ['view/insertElements/perform/after']);
+                });
+                $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElementSplitButtonInside'), template).on('click', function(e) {
+                    getPublisherSubscriber().publish('view/stage/abstract/elementToolbar/button/newElement/clicked', ['view/insertElements/perform/inside']);
+                });
+            } else {
+                getViewModel().hideComponent($(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElementSplitButton'), template));
+
+                $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarNewElement'), template).on('click', function(e) {
+                    getPublisherSubscriber().publish('view/stage/abstract/elementToolbar/button/newElement/clicked', ['view/insertElements/perform/after']);
+                });
+            }
+
+            $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbarRemoveElement'), template).on('click', function(e) {
+                getViewModel().showRemoveFormElementModal();
+            });
+
+            return template;
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param object
+         * @param bool
+         * @return void
+         */
+        function createAndAddAbstractViewFormElementToolbar(selectedFormElementDomElement, formElement, useFadeEffect) {
+            var toolbar;
+            if (getUtility().isUndefinedOrNull(formElement)) {
+                formElement = getCurrentlySelectedFormElement();
+            }
+
+            if (useFadeEffect) {
+                createAbstractViewFormElementToolbar(formElement).fadeOut(0, function() {
+                    selectedFormElementDomElement.prepend($(this));
+                    $(getHelper().getDomElementDataIdentifierSelector('abstractViewToolbar'), selectedFormElementDomElement).fadeIn('fast');
+                });
+            } else {
+                selectedFormElementDomElement.prepend(createAbstractViewFormElementToolbar(formElement));
+            }
+            
+        };
+
+        /**
+         * @public
+         *
+         * @param int
+         * @param function
+         * @return void
+         * @publish view/stage/dnd/stop
+         * @publish view/stage/element/clicked
+         * @throws 1478169511
+         */
+        function renderAbstractStageArea(pageIndex, callback) {
+            if (getUtility().isUndefinedOrNull(pageIndex)) {
+                pageIndex = getFormEditorApp().getCurrentlySelectedPageIndex();
+            }
+            _stageDomElement.off().empty().append(renderFormDefinitionPageAsSortableList(pageIndex));
+
+            _stageDomElement.on("click", function(e) {
+                var formElementIdentifierPath;
+
+                formElementIdentifierPath = $(e.target)
+                    .closest(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey'))
+                    .attr(getHelper().getDomElementDataAttribute('elementIdentifier'));
+                if (
+                    getUtility().isUndefinedOrNull(formElementIdentifierPath)
+                    || !getUtility().isNonEmptyString(formElementIdentifierPath)
+                ) {
+                    return;
+                }
+
+                getPublisherSubscriber().publish('view/stage/element/clicked', [formElementIdentifierPath]);
+            });
+
+            if (_configuration['isSortable']) {
+                _addSortableEvents();
+            }
+
+            if ('function' === $.type(callback)) {
+                callback();
+            }
+        };
+
+
+        /* *************************************************************
+         * Preview stage
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @param string html
+         * @return void
+         * @throws 1475424409
+         */
+        function renderPreviewStageArea(html) {
+            assert(getUtility().isNonEmptyString(html), 'Invalid parameter "html"', 1475424409);
+
+            _stageDomElement.off().empty().html(html);
+
+            $(':input', _stageDomElement).prop('disabled', 'disabled').on('click dblclick select focus keydown keypress keyup mousedown mouseup', function(e) {
+                return e.preventDefault();
+            });
+
+            $('form', _stageDomElement).submit(function(e) {
+                return e.preventDefault();
+            });
+
+            getAllFormElementDomElements().each(function(i, element) {
+                var formElement, metaLabel;
+
+                formElement = getFormEditorApp()
+                    .getFormElementByIdentifierPath($(this).data('elementIdentifierPath'));
+
+                if (
+                    !getFormElementDefinition(formElement, '_isTopLevelFormElement')
+                    && getFormElementDefinition(formElement, '_isCompositeFormElement')
+                ) {
+                    $(this).tooltip({
+                        title: 'identifier: ' + formElement.get('identifier') + ' (type: ' + formElement.get('type') + ')',
+                        placement : 'rigth'
+                    });
+                } else if (
+                    !getFormElementDefinition(formElement, '_isTopLevelFormElement')
+                    && !getFormElementDefinition(formElement, '_isCompositeFormElement')
+                ) {
+                    $(this).tooltip({
+                        title: 'identifier: ' + formElement.get('identifier') + ' (type: ' + formElement.get('type') + ')',
+                        placement : 'left'
+                    });
+                }
+
+                if (getFormElementDefinition(formElement, '_isTopLevelFormElement')) {
+                    $(this).addClass(getHelper().getDomElementClassName('formElementIsTopLevel'));
+                }
+                if (getFormElementDefinition(formElement, '_isCompositeFormElement')) {
+                    $(this).addClass(getHelper().getDomElementClassName('formElementIsComposit'));
+                }
+            });
+
+        };
+
+        /* *************************************************************
+         * Template rendering
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param template
+         * @param function
+         * @return void
+         */
+        function eachTemplateProperty(formElement, template, callback) {
+            $(getHelper().getDomElementDataAttribute('templateProperty', 'bracesWithKey'), template).each(function(i, element) {
+                var propertyPath, propertyValue;
+
+                propertyPath = $(element).attr(getHelper().getDomElementDataAttribute('templateProperty'));
+                propertyValue = formElement.get(propertyPath);
+
+                if ('function' === $.type(callback)) {
+                    callback(propertyPath, propertyValue, element);
+                }
+            });
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         * @return object
+         * @return void
+         */
+        function renderCheckboxTemplate(formElement, template) {
+            renderSimpleTemplateWithValidators(formElement, template);
+
+            eachTemplateProperty(formElement, template, function(propertyPath, propertyValue, domElement) {
+                if (
+                    ('boolean' === $.type(propertyValue) && propertyValue)
+                    || propertyValue === 'true'
+                    || propertyValue === 1
+                    || propertyValue === "1"
+                ) {
+                    $(domElement).addClass(getHelper().getDomElementClassName('noNesting'));
+                }
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         * @return object
+         * @return void
+         * @throws 1479035696
+         */
+        function renderSimpleTemplate(formElement, template) {
+            assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1479035696);
+
+            eachTemplateProperty(formElement, template, function(propertyPath, propertyValue, domElement) {
+                _setTemplateTextContent(domElement, propertyValue);
+            });
+
+            Icons.getIcon(
+                getFormElementDefinition(formElement, 'iconIdentifier'),
+                Icons.sizes.small,
+                null,
+                Icons.states.default,
+                Icons.markupIdentifiers.inline
+            ).done(function(icon) {
+                $(getHelper().getDomElementDataIdentifierSelector('formElementIcon'), template)
+                    .append($(icon).addClass(getHelper().getDomElementClassName('icon')));
+            });
+
+            getHelper()
+                .getTemplatePropertyDomElement('_type', template)
+                .append(formElement.get('type'));
+            getHelper()
+                .getTemplatePropertyDomElement('_identifier', template)
+                .append(formElement.get('identifier'));
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         * @return object
+         * @return void
+         * @throws 1479035674
+         */
+        function renderSimpleTemplateWithValidators(formElement, template) {
+            var validators, validatorsCountWithoutRequired, validatorsTemplateContent;
+            assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1479035674);
+
+            renderSimpleTemplate(formElement, template);
+
+            validatorsTemplateContent = $(
+                getHelper().getDomElementDataIdentifierSelector('validatorsContainer'),
+                $(template)
+            ).clone();
+
+            $(getHelper().getDomElementDataIdentifierSelector('validatorsContainer'), $(template)).empty();
+            validators = formElement.get('validators');
+
+            if ('array' === $.type(validators)) {
+                validatorsCountWithoutRequired = 0;
+                if (validators.length > 0) {
+                    for (var i = 0, len = validators.length; i < len; ++i) {
+                        var collectionElementConfiguration, rowTemplate;
+
+                        if ('NotEmpty' === validators[i]['identifier']) {
+                            getHelper()
+                                .getTemplatePropertyDomElement('_required', template)
+                                .text('*');
+                            continue;
+                        }
+                        validatorsCountWithoutRequired++;
+
+                        collectionElementConfiguration = getFormEditorApp()
+                            .getFormEditorDefinition('validators', validators[i]['identifier']);
+                        rowTemplate = $($(validatorsTemplateContent).clone());
+                        
+                        getHelper()
+                            .getTemplatePropertyDomElement('_label', rowTemplate)
+                            .append(collectionElementConfiguration['label']);
+                        $(getHelper().getDomElementDataIdentifierSelector('validatorsContainer'), $(template))
+                            .append(rowTemplate.html());
+                    }
+
+                    if (validatorsCountWithoutRequired > 0) {
+                        Icons.getIcon(
+                            getHelper().getDomElementDataAttributeValue('iconValidator'),
+                            Icons.sizes.small,
+                            null,
+                            Icons.states.default,
+                            Icons.markupIdentifiers.inline
+                        ).done(function(icon) {
+                            $(getHelper().getDomElementDataIdentifierSelector('validatorIcon'), $(template))
+                                .append($(icon).addClass(getHelper().getDomElementClassName('icon')));
+                        });
+                    }
+                }
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         * @return object
+         * @return void
+         */
+        function renderSelectTemplates(formElement, template) {
+            var appendMultiValue, defaultValue, multiValueTemplateContent, propertyPath, propertyValue;
+
+            multiValueTemplateContent = $(
+                getHelper().getDomElementDataIdentifierSelector('multiValueContainer'),
+                $(template)
+            ).clone();
+            $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template)).empty();
+
+            renderSimpleTemplateWithValidators(formElement, template);
+
+            propertyPath = $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template))
+                .attr(getHelper().getDomElementDataAttribute('templateProperty'));
+
+            propertyValue = formElement.get(propertyPath);
+
+            appendMultiValue = function(label, value, defaultValue) {
+                var isPreselected, rowTemplate;
+
+                isPreselected = false;
+                rowTemplate = $($(multiValueTemplateContent).clone());
+
+                for (var defaultValueKey in defaultValue) {
+                    if (!defaultValue.hasOwnProperty(defaultValueKey)) {
+                        continue;
+                    }
+                    if (defaultValue[defaultValueKey] === value) {
+                        isPreselected = true;
+                        break;
+                    }
+                }
+
+                getHelper().getTemplatePropertyDomElement('_label', rowTemplate).append(label);
+
+                if (isPreselected) {
+                    getHelper().getTemplatePropertyDomElement('_label', rowTemplate).addClass(
+                        getHelper().getDomElementClassName('selected')
+                    );
+                }
+
+                $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template))
+                    .append(rowTemplate.html());
+            };
+
+            defaultValue = formElement.get('defaultValue');
+
+            if (getFormEditorApp().getUtility().isUndefinedOrNull(defaultValue)) {
+                defaultValue = {};
+            } else if ('string' === $.type(defaultValue)) {
+                defaultValue = {0: defaultValue};
+            }
+
+            if ('object' === $.type(propertyValue)) {
+                for (var propertyValueKey in propertyValue) {
+                    if (!propertyValue.hasOwnProperty(propertyValueKey)) {
+                        continue;
+                    }
+                    appendMultiValue(propertyValue[propertyValueKey], propertyValueKey, defaultValue);
+                }
+            } else if ('array' === $.type(propertyValue)) {
+                for (var i = 0, len = propertyValue.length; i < len; ++i) {
+                    appendMultiValue(propertyValue[i]['_label'], propertyValue[i]['_value'], defaultValue);
+                }
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         * @return object
+         * @return void
+         */
+        function renderFileUploadTemplates(formElement, template) {
+            var appendMultiValue, multiValueTemplateContent, propertyPath, propertyValue;
+
+            multiValueTemplateContent = $(
+                getHelper().getDomElementDataIdentifierSelector('multiValueContainer'),
+                $(template)
+            ).clone();
+            $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template)).empty();
+
+            renderSimpleTemplateWithValidators(formElement, template);
+
+            propertyPath = $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template))
+                .attr(getHelper().getDomElementDataAttribute('templateProperty'));
+            propertyValue = formElement.get(propertyPath);
+
+            appendMultiValue = function(value) {
+                var rowTemplate;
+
+                rowTemplate = $($(multiValueTemplateContent).clone());
+
+                getHelper().getTemplatePropertyDomElement('_value', rowTemplate).append(value);
+                $(getHelper().getDomElementDataIdentifierSelector('multiValueContainer'), $(template))
+                    .append(rowTemplate.html());
+            };
+
+            if ('object' === $.type(propertyValue)) {
+                for (var propertyValueKey in propertyValue) {
+                    if (!propertyValue.hasOwnProperty(propertyValueKey)) {
+                        continue;
+                    }
+                    appendMultiValue(propertyValue[propertyValueKey]);
+                }
+            } else if ('array' === $.type(propertyValue)) {
+                for (var i = 0, len = propertyValue.length; i < len; ++i) {
+                    appendMultiValue(propertyValue[i]);
+                }
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param object
+         * @param object
+         * @return this
+         * @throws 1478992119
+         */
+        function bootstrap(formEditorApp, appendToDomElement, configuration) {
+            _formEditorApp = formEditorApp;
+            assert('object' === $.type(appendToDomElement), 'Invalid parameter "appendToDomElement"', 1478992119);
+
+            _stageDomElement = $(appendToDomElement);
+            _configuration = $.extend(true, _defaultConfiguration, configuration || {});
+            _helperSetup();
+            return this;
+        };
+
+        /**
+         * Publish the public methods.
+         * Implements the "Revealing Module Pattern".
+         */
+        return {
+            bootstrap: bootstrap,
+            buildTitleByFormElement: buildTitleByFormElement,
+            createAndAddAbstractViewFormElementToolbar: createAndAddAbstractViewFormElementToolbar,
+            createAbstractViewFormElementToolbar: createAbstractViewFormElementToolbar,
+            eachTemplateProperty: eachTemplateProperty,
+            getAbstractViewFormElementDomElement: getAbstractViewFormElementDomElement,
+            getAbstractViewFormElementWithinDomElement: getAbstractViewFormElementWithinDomElement,
+            getAbstractViewFormElementIdentifierPathWithinDomElement: getAbstractViewFormElementIdentifierPathWithinDomElement,
+            getAbstractViewParentFormElementWithinDomElement: getAbstractViewParentFormElementWithinDomElement,
+            getAbstractViewParentFormElementIdentifierPathWithinDomElement: getAbstractViewParentFormElementIdentifierPathWithinDomElement,
+            getAbstractViewSiblingFormElementIdentifierPathWithinDomElement: getAbstractViewSiblingFormElementIdentifierPathWithinDomElement,
+            getAllFormElementDomElements: getAllFormElementDomElements,
+            getStageDomElement: getStageDomElement,
+            getStagePanelDomElement: getStagePanelDomElement,
+            removeAllStageToolbars: removeAllStageToolbars,
+            renderAbstractStageArea: renderAbstractStageArea,
+            renderCheckboxTemplate: renderCheckboxTemplate,
+            renderFileUploadTemplates: renderFileUploadTemplates,
+            renderFormDefinitionPageAsSortableList: renderFormDefinitionPageAsSortableList,
+            renderPagination: renderPagination,
+            renderPreviewStageArea: renderPreviewStageArea,
+            renderSelectTemplates: renderSelectTemplates,
+            renderSimpleTemplate: renderSimpleTemplate,
+            renderSimpleTemplateWithValidators: renderSimpleTemplateWithValidators,
+            renderUndoRedo: renderUndoRedo,
+            setStageHeadline: setStageHeadline
+        };
+    })($, Helper, Icons);
+});
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/TreeComponent.js b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/TreeComponent.js
new file mode 100644
index 0000000000000000000000000000000000000000..00d890ff3b5a432ee13372d1ee1645dbbca42248
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/TreeComponent.js
@@ -0,0 +1,648 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/Form/Backend/FormEditor/TreeComponent
+ */
+define(['jquery',
+        'TYPO3/CMS/Form/Backend/FormEditor/Helper',
+        'TYPO3/CMS/Backend/Icons',
+        'TYPO3/CMS/Form/Backend/Vendor/jquery.mjs.nestedSortable'
+        ], function($, Helper, Icons) {
+        'use strict';
+
+    return (function($, Helper, Icons) {
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _configuration = null;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _expanderStates = {};
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _defaultConfiguration = {
+            domElementClassNames: {
+                collapsed: 'mjs-nestedSortable-collapsed',
+                expanded: 'mjs-nestedSortable-expanded',
+                hasChildren: 't3-form-element-has-children',
+                sortable: 'sortable',
+                svgLinkWrapper: 'svg-wrapper',
+                noNesting: 'mjs-nestedSortable-no-nesting'
+            },
+            domElementDataAttributeNames: {
+                abstractType: 'data-element-abstract-type'
+            },
+            domElementDataAttributeValues: {
+                collapse: 'actions-pagetree-collapse',
+                expander: 'treeExpander',
+                title: 'treeTitle'
+            },
+            isSortable: true,
+            svgLink: {
+                height: 15,
+                paths: {
+                    angle: 'M0 0 V21 H15',
+                    vertical: 'M0 0 V21 H0',
+                    hidden: 'M0 0 V0 H0'
+                },
+                width: 15
+            }
+        };
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _formEditorApp = null;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _treeDomElement = null;
+
+        /* *************************************************************
+         * Private Methodes
+         * ************************************************************/
+
+        /**
+         * @private
+         *
+         * @return void
+         * @throws 1478268638
+         */
+        function _helperSetup() {
+            assert('function' === $.type(Helper.bootstrap),
+                'The view model helper does not implement the method "bootstrap"',
+                1478268638
+            );
+            Helper.bootstrap(getFormEditorApp());
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getFormEditorApp() {
+            return _formEditorApp;
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return object
+         */
+        function getHelper(configuration) {
+            if (getUtility().isUndefinedOrNull(configuration)) {
+                return Helper.setConfiguration(_configuration);
+            }
+            return Helper.setConfiguration(configuration);
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getUtility() {
+            return getFormEditorApp().getUtility();
+        };
+
+        /**
+         * @private
+         *
+         * @param mixed test
+         * @param string message
+         * @param int messageCode
+         * @return void
+         */
+        function assert(test, message, messageCode) {
+            return getFormEditorApp().assert(test, message, messageCode);
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getRootFormElement() {
+            return getFormEditorApp().getRootFormElement();
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getCurrentlySelectedFormElement() {
+            return getFormEditorApp().getCurrentlySelectedFormElement();
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getPublisherSubscriber() {
+            return getFormEditorApp().getPublisherSubscriber();
+        };
+
+        /**
+         * @private
+         *
+         * @param object
+         * @param string
+         * @return mixed
+         */
+        function getFormElementDefinition(formElement, formElementDefinitionKey) {
+            return getFormEditorApp().getFormElementDefinition(formElement, formElementDefinitionKey);
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function _getLinkSvg(type) {
+            return $('<span class="' + getHelper().getDomElementClassName('svgLinkWrapper') + '">'
+                       + '<svg version="1.1" width="' + _configuration['svgLink']['width'] + '" height="' + _configuration['svgLink']['height'] + '">'
+                           + '<path class="link" d="' + _configuration['svgLink']['paths'][type] + '">'
+                       + '</svg>'
+                   + '</span>');
+        };
+
+        /**
+         * @private
+         *
+         * @param object
+         * @return object
+         * @publish view/tree/render/listItemAdded
+         * @throws 1478715704
+         */
+        function _renderNestedSortableListItem(formElement) {
+            var childFormElements, childList, expanderItem, isLastFormElementWithinParentFormElement, listItem, listItemContent, searchElement;
+            assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1478715704);
+
+            isLastFormElementWithinParentFormElement = false;
+            if (formElement.get('__identifierPath') === getFormEditorApp().getLastFormElementWithinParentFormElement(formElement).get('__identifierPath')) {
+                isLastFormElementWithinParentFormElement = true;
+            }
+
+            listItem = $('<li></li>');
+            if (!getFormElementDefinition(formElement, '_isCompositeFormElement')) {
+                listItem.addClass(getHelper().getDomElementClassName('noNesting'));
+            }
+
+            listItemContent = $('<div></div>')
+                .attr(getHelper().getDomElementDataAttribute('elementIdentifier'), formElement.get('__identifierPath'))
+                .append(
+                    $('<span></span>')
+                        .attr(getHelper().getDomElementDataAttribute('identifier'), getHelper().getDomElementDataAttributeValue('title'))
+                        .html(buildTitleByFormElement(formElement))
+                );
+
+            if (getFormElementDefinition(formElement, '_isCompositeFormElement')) {
+                listItemContent.attr(getHelper().getDomElementDataAttribute('abstractType'), 'isCompositeFormElement');
+            }
+            if (getFormElementDefinition(formElement, '_isTopLevelFormElement')) {
+                listItemContent.attr(getHelper().getDomElementDataAttribute('abstractType'), 'isTopLevelFormElement');
+            }
+
+            expanderItem = $('<span></span>').attr('data-identifier', getHelper().getDomElementDataAttributeValue('expander'));
+            listItemContent.prepend(expanderItem);
+
+            Icons.getIcon(getFormElementDefinition(formElement, 'iconIdentifier'), Icons.sizes.small, null, Icons.states.default).done(function(icon) {
+                expanderItem.after(
+                    $(icon).addClass(getHelper().getDomElementClassName('icon'))
+                        .tooltip({
+                            title: 'identifier: ' + formElement.get('identifier'),
+                            placement: 'right'
+                        })
+                );
+
+                if (getFormElementDefinition(formElement, '_isCompositeFormElement')) {
+                    if (formElement.get('renderables') && formElement.get('renderables').length > 0) {
+                        Icons.getIcon(getHelper().getDomElementDataAttributeValue('collapse'), Icons.sizes.small).done(function(icon) {
+                            expanderItem.before(_getLinkSvg('angle')).html($(icon));
+                            listItem.addClass(getHelper().getDomElementClassName('hasChildren'));
+                        });
+                    } else {
+                        expanderItem.before(_getLinkSvg('angle')).remove();
+                    }
+                } else {
+                    listItemContent.prepend(_getLinkSvg('angle'));
+                    expanderItem.remove();
+                }
+
+                searchElement = formElement.get('__parentRenderable');
+                while (searchElement) {
+                    if (searchElement.get('__identifierPath') === getRootFormElement().get('__identifierPath')) {
+                        break;
+                    }
+
+                    if (searchElement.get('__identifierPath') === getFormEditorApp().getLastFormElementWithinParentFormElement(searchElement).get('__identifierPath')) {
+                        listItemContent.prepend(_getLinkSvg('hidden'));
+                    } else {
+                        listItemContent.prepend(_getLinkSvg('vertical'));
+                    }
+                    searchElement = searchElement.get('__parentRenderable');
+                }
+            });
+            listItem.append(listItemContent);
+
+            getPublisherSubscriber().publish('view/tree/render/listItemAdded', [listItem, formElement]);
+            childFormElements = formElement.get('renderables');
+            childList = null;
+            if ('array' === $.type(childFormElements)) {
+                childList = $('<ol></ol>');
+                for (var i = 0, len = childFormElements.length; i < len; ++i) {
+                    childList.append(_renderNestedSortableListItem(childFormElements[i]));
+                }
+            }
+
+            if (childList) {
+                listItem.append(childList);
+            }
+            return listItem;
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         * @publish view/tree/dnd/stop
+         * @publish view/tree/dnd/change
+         * @publish view/tree/dnd/update
+         */
+        function _addSortableEvents() {
+            $('ol.' + getHelper().getDomElementClassName('sortable'), _treeDomElement).nestedSortable({
+                forcePlaceholderSize: true,
+                protectRoot: true,
+                isTree: true,
+                handle: 'div' + getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey'),
+                helper:	'clone',
+                items: 'li',
+                opacity: .6,
+                revert: 250,
+                delay: 200,
+                tolerance: 'pointer',
+                toleranceElement: '> div',
+
+                stop: function(e, o) {
+                    getPublisherSubscriber().publish('view/tree/dnd/stop', [getTreeNodeIdentifierPathWithinDomElement($(o.item))]);
+                },
+                change: function(e, o) {
+                    var enclosingCompositeFormElement, parentFormElementIdentifierPath;
+
+                    parentFormElementIdentifierPath = getParentTreeNodeIdentifierPathWithinDomElement($(o.placeholder));
+                    if (parentFormElementIdentifierPath) {
+                        enclosingCompositeFormElement = getFormEditorApp().findEnclosingCompositeFormElementWhichIsNotOnTopLevel(parentFormElementIdentifierPath);
+                    }
+                    getPublisherSubscriber().publish('view/tree/dnd/change', [$(o.placeholder), parentFormElementIdentifierPath, enclosingCompositeFormElement]);
+                },
+                update: function(e, o) {
+                    var nextFormElementIdentifierPath, movedFormElementIdentifierPath, previousFormElementIdentifierPath;
+
+                    movedFormElementIdentifierPath = getTreeNodeIdentifierPathWithinDomElement($(o.item));
+                    previousFormElementIdentifierPath = getSiblingTreeNodeIdentifierPathWithinDomElement($(o.item), 'prev');
+                    nextFormElementIdentifierPath = getSiblingTreeNodeIdentifierPathWithinDomElement($(o.item), 'next');
+
+                    getPublisherSubscriber().publish('view/tree/dnd/update', [$(o.item), movedFormElementIdentifierPath, previousFormElementIdentifierPath, nextFormElementIdentifierPath]);
+                }
+            });
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         */
+        function _saveExpanderStates() {
+            var addStates;
+
+            addStates = function(formElement) {
+                var childFormElements, treeNode;
+
+                if (getFormElementDefinition(formElement, '_isCompositeFormElement')) {
+                    treeNode = getTreeNode(formElement);
+                    if (treeNode.length) {
+                        if (treeNode.closest('li').hasClass(getHelper().getDomElementClassName('expanded'))) {
+                            _expanderStates[formElement.get('__identifierPath')] = true;
+                        } else {
+                            _expanderStates[formElement.get('__identifierPath')] = false;
+                        }
+                    }
+
+                    if (getUtility().isUndefinedOrNull(_expanderStates[formElement.get('__identifierPath')])) {
+                        _expanderStates[formElement.get('__identifierPath')] = true; 
+                    }
+                }
+
+                childFormElements = formElement.get('renderables');
+                if ('array' === $.type(childFormElements)) {
+                    for (var i = 0, len = childFormElements.length; i < len; ++i) {
+                        addStates(childFormElements[i]);
+                    }
+                }
+            };
+            addStates(getRootFormElement());
+
+            for (var identifierPath in _expanderStates) {
+                if (!_expanderStates.hasOwnProperty(identifierPath)) {
+                    continue;
+                }
+                try {
+                    getFormEditorApp().getFormElementByIdentifierPath(identifierPath);
+                } catch(error) {
+                    delete _expanderStates[identifierPath];
+                }
+            }
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         */
+        function _loadExpanderStates() {
+            for (var identifierPath in _expanderStates) {
+                var treeNode;
+
+                if (!_expanderStates.hasOwnProperty(identifierPath)) {
+                    continue;
+                }
+                treeNode = getTreeNode(identifierPath);
+                if (treeNode.length) {
+                    if (_expanderStates[identifierPath]) {
+                        treeNode.closest('li')
+                            .removeClass(getHelper().getDomElementClassName('collapsed'))
+                            .addClass(getHelper().getDomElementClassName('expanded'));
+                    } else {
+                        treeNode.closest('li')
+                            .addClass(getHelper().getDomElementClassName('collapsed'))
+                            .removeClass(getHelper().getDomElementClassName('expanded'));
+                    }
+                }
+            }
+        };
+
+        /* *************************************************************
+         * Public Methodes
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return object
+         * @throws 1478721208
+         */
+        function renderCompositeFormElementChildsAsSortableList(formElement) {
+            var elementList;
+            assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1478721208);
+
+            elementList = $('<ol></ol>').addClass(getHelper().getDomElementClassName('sortable'));
+            if ('array' === $.type(formElement.get('renderables'))) {
+                for (var i = 0, len = formElement.get('renderables').length; i < len; ++i) {
+                    elementList.append(_renderNestedSortableListItem(formElement.get('renderables')[i]));
+                }
+            }
+            return elementList;
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         * @param object
+         * @publish view/tree/node/clicked
+         */
+        function renew(formElement) {
+            if (getFormEditorApp().getUtility().isUndefinedOrNull(formElement)) {
+                formElement = getRootFormElement();
+            }
+            _saveExpanderStates();
+            _treeDomElement.off().empty().append(renderCompositeFormElementChildsAsSortableList(formElement));
+
+            _treeDomElement.on("click", function(e) {
+                var formElementIdentifierPath;
+
+                formElementIdentifierPath = $(e.target)
+                    .closest(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey'))
+                    .attr(getHelper().getDomElementDataAttribute('elementIdentifier'));
+                if (getUtility().isUndefinedOrNull(formElementIdentifierPath) || !getUtility().isNonEmptyString(formElementIdentifierPath)) {
+                    return;
+                }
+                getPublisherSubscriber().publish('view/tree/node/clicked', [formElementIdentifierPath]);
+            });
+
+			$(getHelper().getDomElementDataIdentifierSelector('expander'), _treeDomElement).on('click', function() {
+				$(this).closest('li').toggleClass(getHelper().getDomElementClassName('collapsed')).toggleClass(getHelper().getDomElementClassName('expanded'));
+			});
+
+            if (_configuration['isSortable']) {
+                _addSortableEvents();
+            }
+            _loadExpanderStates();
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return string
+         */
+        function getAllTreeNodes() {
+            return $(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey'), _treeDomElement);
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return string
+         */
+        function getTreeNodeWithinDomElement(element) {
+            return $(element).find(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey')).first();
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return string
+         */
+        function getTreeNodeIdentifierPathWithinDomElement(element) {
+            return getTreeNodeWithinDomElement($(element)).attr(getHelper().getDomElementDataAttribute('elementIdentifier'));
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return string
+         */
+        function getParentTreeNodeWithinDomElement(element) {
+            return $(element).parent().closest('li').find(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey')).first();
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return string
+         */
+        function getParentTreeNodeIdentifierPathWithinDomElement(element) {
+            return getParentTreeNodeWithinDomElement(element).attr(getHelper().getDomElementDataAttribute('elementIdentifier'));
+        };
+
+        /**
+         * @private
+         *
+         * @param object
+         * @param string
+         * @return string
+         */
+        function getSiblingTreeNodeIdentifierPathWithinDomElement(element, position) {
+            var formElementIdentifierPath;
+
+            if (getUtility().isUndefinedOrNull(position)) {
+                position = 'prev';
+            }
+            formElementIdentifierPath = getTreeNodeIdentifierPathWithinDomElement(element);
+            element = (position === 'prev') ? $(element).prev('li') : $(element).next('li');
+            return element.find(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKey'))
+                .not(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKeyValue', [formElementIdentifierPath]))
+                .first()
+                .attr(getHelper().getDomElementDataAttribute('elementIdentifier'));
+        };
+
+        /**
+         * @public
+         *
+         * @param string
+         * @param object
+         * @return void
+         */
+        function setTreeNodeTitle(title, formElement) {
+            if (getUtility().isUndefinedOrNull(title)) {
+                title = buildTitleByFormElement(formElement);
+            }
+
+            $(getHelper().getDomElementDataIdentifierSelector('title'), getTreeNode(formElement)).html(title);
+        };
+
+        /**
+         * @public
+         *
+         * @param string|object
+         * @return object
+         */
+        function getTreeNode(formElement) {
+            var formElementIdentifierPath;
+
+            if ('string' === $.type(formElement)) {
+                formElementIdentifierPath = formElement;
+            } else {
+                if (getUtility().isUndefinedOrNull(formElement)) {
+                    formElementIdentifierPath = getCurrentlySelectedFormElement().get('__identifierPath');
+                } else {
+                    formElementIdentifierPath = formElement.get('__identifierPath');
+                }
+            }
+            return $(getHelper().getDomElementDataAttribute('elementIdentifier', 'bracesWithKeyValue', [formElementIdentifierPath]), _treeDomElement);
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return object
+         * @throws 1478719287
+         */
+        function buildTitleByFormElement(formElement) {
+            if (getUtility().isUndefinedOrNull(formElement)) {
+                formElement = getCurrentlySelectedFormElement();
+            }
+            assert('object' === $.type(formElement), 'Invalid parameter "formElement"', 1478719287);
+
+            return $('<span></span>')
+                .text((formElement.get('label') ? formElement.get('label') : formElement.get('identifier')))
+                .append($('<small></small>').text("(" + getFormElementDefinition(formElement, 'label') + ")"));
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function getTreeDomElement() {
+            return _treeDomElement;
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param object
+         * @param object
+         * @return this
+         * @throws 1478714814
+         */
+        function bootstrap(formEditorApp, appendToDomElement, configuration) {
+            _formEditorApp = formEditorApp;
+            assert('object' === $.type(appendToDomElement), 'Invalid parameter "appendToDomElement"', 1478714814);
+
+            _treeDomElement = $(appendToDomElement);
+            _configuration = $.extend(true, _defaultConfiguration, configuration || {});
+            _helperSetup();
+            return this;
+        };
+
+        /**
+         * Publish the public methods.
+         * Implements the "Revealing Module Pattern".
+         */
+        return {
+            bootstrap: bootstrap,
+            buildTitleByFormElement: buildTitleByFormElement,
+            getAllTreeNodes: getAllTreeNodes,
+            getParentTreeNodeWithinDomElement: getParentTreeNodeWithinDomElement,
+            getParentTreeNodeIdentifierPathWithinDomElement: getParentTreeNodeIdentifierPathWithinDomElement,
+            getSiblingTreeNodeIdentifierPathWithinDomElement: getSiblingTreeNodeIdentifierPathWithinDomElement,
+            getTreeDomElement: getTreeDomElement,
+            getTreeNode: getTreeNode,
+            getTreeNodeWithinDomElement: getTreeNodeWithinDomElement,
+            getTreeNodeIdentifierPathWithinDomElement: getTreeNodeIdentifierPathWithinDomElement,
+            renderCompositeFormElementChildsAsSortableList: renderCompositeFormElementChildsAsSortableList,
+            renew: renew,
+            setTreeNodeTitle: setTreeNodeTitle
+        };
+    })($, Helper, Icons);
+});
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/ViewModel.js b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/ViewModel.js
new file mode 100644
index 0000000000000000000000000000000000000000..f4fd8e48209ad7c440f88153f02596689088a2ca
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/ViewModel.js
@@ -0,0 +1,1697 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/Form/Backend/FormEditor/ViewModel
+ */
+define(['jquery',
+        'TYPO3/CMS/Form/Backend/FormEditor/TreeComponent',
+        'TYPO3/CMS/Form/Backend/FormEditor/ModalsComponent',
+        'TYPO3/CMS/Form/Backend/FormEditor/InspectorComponent',
+        'TYPO3/CMS/Form/Backend/FormEditor/StageComponent',
+        'TYPO3/CMS/Form/Backend/FormEditor/Helper',
+        'TYPO3/CMS/Backend/Icons',
+        'TYPO3/CMS/Backend/Notification'
+        ], function($, TreeComponent, ModalsComponent, InspectorComponent, StageComponent, Helper, Icons, Notification) {
+        'use strict';
+
+    return (function($, TreeComponent, ModalsComponent, InspectorComponent, StageComponent, Helper, Icons, Notification) {
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _configuration = {
+            domElementClassNames: {
+                formElementIsComposit: 't3-form-element-composit',
+                formElementIsTopLevel: 't3-form-element-toplevel',
+                hasError: 'has-error',
+                headerButtonBar: 'module-docheader-bar-column-left',
+                selectedCompositFormElement: 't3-form-form-composit-element-selected',
+                selectedFormElement: 't3-form-form-element-selected',
+                selectedRootFormElement: 't3-form-root-element-selected',
+                selectedStagePanel: 't3-form-form-stage-selected',
+                sortableHover: 'sortable-hover',
+                stageViewModeAbstract: 't3-form-stage-viewmode-abstract',
+                stageViewModePreview: 't3-form-stage-viewmode-preview',
+                validationErrors: 't3-form-validation-errors',
+                validationChildHasErrors: 't3-form-validation-child-has-error'
+            },
+            domElementDataAttributeNames: {
+                abstractType: 'data-element-abstract-type'
+            },
+            domElementDataAttributeValues: {
+                buttonHeaderClose: 'closeButton',
+                buttonHeaderNewPage: 'headerNewPage',
+                buttonHeaderPaginationNext: 'buttonPaginationNext',
+                buttonHeaderPaginationPrevious: 'buttonPaginationPrevious',
+                buttonHeaderRedo: 'redoButton',
+                buttonHeaderSave: 'saveButton',
+                buttonHeaderUndo: 'undoButton',
+                buttonHeaderViewModeAbstract: 'buttonViewModeAbstract',
+                buttonHeaderViewModePreview: 'buttonViewModePreview',
+                buttonStageNewElementBottom: 'stageNewElementBottom',
+                buttonStructureNewPage: 'treeNewPageBottom',
+                iconMailform: 'content-elements-mailform',
+                iconSave: 'actions-document-save',
+                iconSaveSpinner: 'spinner-circle-dark',
+                inspectorSection: 'inspectorSection',
+                moduleLoadingIndicator: 'moduleLoadingIndicator',
+                moduleWrapper: 'moduleWrapper',
+                stageArea: 'stageArea',
+                stageContainer: 'stageContainer',
+                stageNewElementRow: 'stageNewElementRow',
+                stagePanelHeading: 'panelHeading',
+                stageSection: 'stageSection',
+                structure: 'structure-element',
+                structureSection: 'structureSection',
+                structureRootContainer: 'treeRootContainer',
+                structureRootElement: 'treeRootElement'
+            },
+            panels: {
+                structure: {
+                    width: 300
+                },
+                stage: {
+                    marginLeft: 300,
+                    marginRight: 325,
+                    marginLeftCollapsed: 0,
+                    marginRightCollapsed: -25
+                },
+                inspector: {
+                    width: 350
+                }
+            }
+        };
+
+        /**
+         * @private
+         *
+         * @var bool
+         */
+        var _previewMode = false;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _formEditorApp = null;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _structureComponent = null;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _modalsComponent = null;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _inspectorsComponent = null;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _stageComponent = null;
+
+        /* *************************************************************
+         * Private Methodes
+         * ************************************************************/
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getRootFormElement() {
+            return getFormEditorApp().getRootFormElement();
+        };
+
+        /**
+         * @private
+         *
+         * @param mixed test
+         * @param string message
+         * @param int messageCode
+         * @return void
+         */
+        function assert(test, message, messageCode) {
+            return getFormEditorApp().assert(test, message, messageCode);
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getUtility() {
+            return getFormEditorApp().getUtility();
+        };
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getCurrentlySelectedFormElement() {
+            return getFormEditorApp().getCurrentlySelectedFormElement();
+        };
+
+
+        /**
+         * @private
+         *
+         * @return object
+         */
+        function getPublisherSubscriber() {
+            return getFormEditorApp().getPublisherSubscriber();
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         */
+        function _addPropertyValidators() {
+            getFormEditorApp().addPropertyValidationValidator('NotEmpty', function(formElement, propertyPath) {
+                if (formElement.get(propertyPath) === '') {
+                    return getFormEditorApp().getFormElementPropertyValidatorDefinition('NotEmpty')['errorMessage'] || 'invalid value';
+                }
+            });
+
+            getFormEditorApp().addPropertyValidationValidator('Integer', function(formElement, propertyPath) {
+                if (!$.isNumeric(formElement.get(propertyPath))) {
+                    return getFormEditorApp().getFormElementPropertyValidatorDefinition('Integer')['errorMessage'] || 'invalid value';
+                }
+            });
+
+            getFormEditorApp().addPropertyValidationValidator('NaiveEmail', function(formElement, propertyPath) {
+                if (!formElement.get(propertyPath).match(/\S+@\S+\.\S+/)) {
+                    return getFormEditorApp().getFormElementPropertyValidatorDefinition('NaiveEmail')['errorMessage'] || 'invalid value';
+                }
+            });
+
+            getFormEditorApp().addPropertyValidationValidator('NaiveEmailOrEmpty', function(formElement, propertyPath) {
+                if (formElement.get(propertyPath).length > 0 && !formElement.get(propertyPath).match(/\S+@\S+\.\S+/)) {
+                    return getFormEditorApp().getFormElementPropertyValidatorDefinition('NaiveEmailOrEmpty')['errorMessage'] || 'invalid value';
+                }
+            });
+
+            getFormEditorApp().addPropertyValidationValidator('FormElementIdentifierWithinCurlyBracesInclusive', function(formElement, propertyPath) {
+                var match, regex;
+                regex = /\{([a-z0-9-_]+)?\}/gi;
+                match = regex.exec(formElement.get(propertyPath));
+                if (match && ((match[1] && !getFormEditorApp().isFormElementIdentifierUsed(match[1])) || !match[1])) {
+                    return getFormEditorApp().getFormElementPropertyValidatorDefinition('FormElementIdentifierWithinCurlyBracesInclusive')['errorMessage'] || 'invalid value';
+                }
+            });
+
+            getFormEditorApp().addPropertyValidationValidator('FormElementIdentifierWithinCurlyBracesExclusive', function(formElement, propertyPath) {
+                var match, regex;
+                regex = /^\{([a-z0-9-_]+)?\}$/i;
+                match = regex.exec(formElement.get(propertyPath));
+                if (!match || ((match[1] && !getFormEditorApp().isFormElementIdentifierUsed(match[1])) || !match[1])) {
+                    return getFormEditorApp().getFormElementPropertyValidatorDefinition('FormElementIdentifierWithinCurlyBracesInclusive')['errorMessage'] || 'invalid value';
+                }
+            });
+        };
+
+        /**
+         * @private
+         *
+         * @param object additionalViewModelModules
+         * @return void
+         * @publish view/ready
+         * @throws 1475425785
+         */
+        function _loadAdditionalModules(additionalViewModelModules) {
+            var additionalViewModelModulesLength, isLastElement, loadedAdditionalViewModelModules;
+
+            if ('array' !== $.type(additionalViewModelModules)) {
+                return;
+            }
+            additionalViewModelModulesLength = additionalViewModelModules.length;
+
+            if (additionalViewModelModulesLength > 0) {
+                loadedAdditionalViewModelModules = 0;
+                for (var i = 0; i < additionalViewModelModulesLength; ++i) {
+                    require([additionalViewModelModules[i]], function (additionalViewModelModule) {
+                        assert(
+                            'function' === $.type(additionalViewModelModule.bootstrap),
+                            'The module "' + additionalViewModelModules[i] + '" does not implement the method "bootstrap"',
+                            1475425785
+                        );
+                        additionalViewModelModule.bootstrap(getFormEditorApp());
+
+                        loadedAdditionalViewModelModules++;
+                        if (additionalViewModelModulesLength === loadedAdditionalViewModelModules) {
+                            getPublisherSubscriber().publish('view/ready');
+                        }
+                    });
+                }
+            } else {
+                getPublisherSubscriber().publish('view/ready');
+            }
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         * @throws 1478268638
+         */
+        function _helperSetup() {
+            assert('function' === $.type(Helper.bootstrap),
+                'The view model helper does not implement the method "bootstrap"',
+                1478268638
+            );
+
+            Helper.bootstrap(getFormEditorApp());
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         * @throws 1478268639
+         */
+        function _structureComponentSetup() {
+            assert(
+                'function' === $.type(TreeComponent.bootstrap),
+                'The structure component does not implement the method "bootstrap"',
+                1478268639
+            );
+
+            _structureComponent = TreeComponent.bootstrap(
+                getFormEditorApp(),
+                $(getHelper().getDomElementDataAttribute('identifier', 'bracesWithKeyValue', [
+                    getHelper().getDomElementDataAttributeValue('structure')
+                ]))
+            );
+
+            $(  getHelper().getDomElementDataIdentifierSelector('iconMailform'),
+                $(getHelper().getDomElementDataIdentifierSelector('structureRootContainer'))
+            ).tooltip({
+                title: 'identifier: ' + getRootFormElement().get('identifier'),
+                placement: 'right'
+            });
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         * @throws 1478895106
+         */
+        function _modalsComponentSetup() {
+            assert(
+                'function' === $.type(ModalsComponent.bootstrap),
+                'The modals component does not implement the method "bootstrap"',
+                1478895106
+            );
+            _modalsComponent = ModalsComponent.bootstrap(getFormEditorApp());
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         * @throws 1478895106
+         */
+        function _inspectorsComponentSetup() {
+            assert(
+                'function' === $.type(InspectorComponent.bootstrap),
+                'The inspector component does not implement the method "bootstrap"',
+                1478895106
+            );
+            _inspectorsComponent = InspectorComponent.bootstrap(getFormEditorApp());
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         * @throws 1478986610
+         */
+        function _stageComponentSetup() {
+            assert(
+                'function' === $.type(InspectorComponent.bootstrap),
+                'The stage component does not implement the method "bootstrap"',
+                1478986610
+            );
+            _stageComponent = StageComponent.bootstrap(
+                getFormEditorApp(),
+                $(getHelper().getDomElementDataAttribute('identifier', 'bracesWithKeyValue', [
+                    getHelper().getDomElementDataAttributeValue('stageArea')
+                ]))
+            );
+
+            getStage().getStagePanelDomElement().on("click", function(e) {
+                if (
+                    $(e.target).attr(getHelper().getDomElementDataAttribute('identifier')) ===  getHelper().getDomElementDataAttributeValue('stagePanelHeading')
+                    || $(e.target).attr(getHelper().getDomElementDataAttribute('identifier')) ===  getHelper().getDomElementDataAttributeValue('stageSection')
+                    || $(e.target).attr(getHelper().getDomElementDataAttribute('identifier')) ===  getHelper().getDomElementDataAttributeValue('stageArea')
+                ) {
+                    selectPageBatch(getFormEditorApp().getCurrentlySelectedPageIndex());
+                }
+                getPublisherSubscriber().publish('view/stage/panel/clicked', []);
+            });
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         * @publish view/header/button/save/clicked
+         * @publish view/stage/abstract/button/newElement/clicked
+         * @publish view/header/button/newPage/clicked
+         * @publish view/structure/button/newPage/clicked
+         * @publish view/header/button/close/clicked
+         */
+        function _buttonsSetup() {
+            $(getHelper().getDomElementDataIdentifierSelector('buttonHeaderSave')).on("click", function(e) {
+                getPublisherSubscriber().publish('view/header/button/save/clicked', []);
+            });
+
+            $(getHelper().getDomElementDataIdentifierSelector('buttonStageNewElementBottom')).on('click', function(e) {
+                getPublisherSubscriber().publish('view/stage/abstract/button/newElement/clicked', ['view/insertElements/perform/bottom']);
+            });
+
+            $(getHelper().getDomElementDataIdentifierSelector('buttonHeaderNewPage')).on('click', function(e) {
+                getPublisherSubscriber().publish('view/header/button/newPage/clicked', ['view/insertPages/perform']);
+            });
+
+            $(getHelper().getDomElementDataIdentifierSelector('buttonStructureNewPage')).on('click', function(e) {
+                getPublisherSubscriber().publish('view/structure/button/newPage/clicked', ['view/insertPages/perform']);
+            });
+
+            $(getHelper().getDomElementDataIdentifierSelector('buttonHeaderClose')).on('click', function(e) {
+                if (!getFormEditorApp().getUnsavedContent()) {
+                    return;
+                }
+                e.preventDefault();
+                getPublisherSubscriber().publish('view/header/button/close/clicked', []);
+            });
+
+            $(getHelper().getDomElementDataIdentifierSelector('buttonHeaderUndo')).on('click', function(e) {
+                getPublisherSubscriber().publish('view/undoButton/clicked', []);
+            });
+
+            $(getHelper().getDomElementDataIdentifierSelector('buttonHeaderRedo')).on('click', function(e) {
+                getPublisherSubscriber().publish('view/redoButton/clicked', []);
+            });
+
+            $(getHelper().getDomElementDataIdentifierSelector('buttonHeaderViewModeAbstract')).on('click', function(e) {
+                getPublisherSubscriber().publish('view/viewModeButton/abstract/clicked', []);
+            });
+
+            $(getHelper().getDomElementDataIdentifierSelector('buttonHeaderViewModePreview')).on('click', function(e) {
+                getPublisherSubscriber().publish('view/viewModeButton/preview/clicked', []);
+            });
+
+            $(getHelper().getDomElementDataIdentifierSelector('structureRootContainer')).on("click", function(e) {
+                getPublisherSubscriber().publish('view/structure/root/selected');
+            });
+
+            $(getHelper().getDomElementDataIdentifierSelector('buttonHeaderPaginationNext')).on('click', function(e) {
+                getPublisherSubscriber().publish('view/paginationNext/clicked', []);
+            });
+
+            $(getHelper().getDomElementDataIdentifierSelector('buttonHeaderPaginationPrevious')).on('click', function(e) {
+                getPublisherSubscriber().publish('view/paginationPrevious/clicked', []);
+            });
+        };
+
+        /* *************************************************************
+         * Public Methodes
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function getFormEditorApp() {
+            return _formEditorApp;
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return object
+         */
+        function getHelper(configuration) {
+            if (getUtility().isUndefinedOrNull(configuration)) {
+                return Helper.setConfiguration(_configuration);
+            }
+            return Helper.setConfiguration(configuration);
+        };
+
+        /**
+         * @public
+         *
+         * @param object formElement
+         * @param string formElementDefinitionKey
+         * @return mixed
+         */
+        function getFormElementDefinition(formElement, formElementDefinitionKey) {
+            return getFormEditorApp().getFormElementDefinition(formElement, formElementDefinitionKey);
+        };
+
+        /**
+         * @public
+         *
+         * @return object (derefernced)
+         */
+        function getConfiguration() {
+            return $.extend(true, {}, _configuration);
+        };
+
+        /**
+         * @public
+         *
+         * @return int
+         */
+        function getPreviewMode() {
+            return _previewMode;
+        };
+
+        /**
+         * @public
+         *
+         * @param bool 
+         * @return void
+         */
+        function setPreviewMode(previewMode) {
+            _previewMode = !!previewMode;
+        };
+
+        /* *************************************************************
+         * Structure
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function getStructure() {
+            return _structureComponent;
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         * @publish view/structure/renew/postProcess
+         */
+        function renewStructure() {
+            getStructure().renew();
+            getPublisherSubscriber().publish('view/structure/renew/postProcess');
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return void
+         */
+        function addStructureSelection(formElement) {
+            getStructure().getTreeNode(formElement).addClass(getHelper().getDomElementClassName('selectedFormElement'));
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return void
+         */
+        function removeStructureSelection(formElement) {
+            getStructure().getTreeNode(formElement).removeClass(getHelper().getDomElementClassName('selectedFormElement'));
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function removeAllStructureSelections() {
+            $(getHelper().getDomElementClassName('selectedFormElement', true), getStructure().getTreeDomElement())
+                .removeClass(getHelper().getDomElementClassName('selectedFormElement'));
+        };
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function getStructureRootElement() {
+            return $(getHelper().getDomElementDataAttribute('identifier', 'bracesWithKeyValue', [
+                getHelper().getDomElementDataAttributeValue('structureRootElement')
+            ]));
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function removeStructureRootElementSelection() {
+            $(getHelper().getDomElementDataAttribute('identifier', 'bracesWithKeyValue', [
+                getHelper().getDomElementDataAttributeValue('structureRootContainer')
+            ])).removeClass(getHelper().getDomElementClassName('selectedRootFormElement'));
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function addStructureRootElementSelection() {
+            $(getHelper().getDomElementDataAttribute('identifier', 'bracesWithKeyValue', [
+                getHelper().getDomElementDataAttributeValue('structureRootContainer')
+            ])).addClass(getHelper().getDomElementClassName('selectedRootFormElement'));
+        };
+
+        /**
+         * @public
+         *
+         * @param string title
+         * @return void
+         */
+        function setStructureRootElementTitle(title) {
+            if (getUtility().isUndefinedOrNull(title)) {
+                title = $('<span></span>')
+                    .text((getRootFormElement().get('label') ? getRootFormElement().get('label') : getRootFormElement().get('identifier')))
+                    .html();
+            }
+            getStructureRootElement().text(title);
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function addStructureValidationResults() {
+            var validationResults;
+
+            getStructure().getAllTreeNodes()
+                .removeClass(getHelper().getDomElementClassName('validationErrors'))
+                .removeClass(getHelper().getDomElementClassName('validationChildHasErrors'));
+
+            removeElementValidationErrorClass(getStructureRootElement());
+
+            validationResults = getFormEditorApp().validateFormElementRecursive(getRootFormElement());
+            for (var i = 0, len = validationResults.length; i < len; ++i) {
+                var hasError = false, pathParts, validationElement;
+                for (var j = 0, len2 = validationResults[i]['validationResults'].length; j < len2; ++j) {
+                    if (
+                        validationResults[i]['validationResults'][j]['validationResults']
+                        && validationResults[i]['validationResults'][j]['validationResults'].length > 0
+                    ) {
+                        hasError = true;
+                        break;
+                    }
+                }
+
+                if (hasError) {
+                    if (i === 0) {
+                        setElementValidationErrorClass(getStructureRootElement());
+                    } else {
+                        validationElement = getStructure().getTreeNode(validationResults[i]['formElementIdentifierPath']);
+                        setElementValidationErrorClass(validationElement);
+
+                        pathParts = validationResults[i]['formElementIdentifierPath'].split('/');
+                        while(pathParts.pop()) {
+                            validationElement = getStructure().getTreeNode(pathParts.join('/'));
+                            if ('object' === $.type(validationElement)) {
+                                setElementValidationErrorClass(validationElement, 'validationChildHasErrors');
+                            }
+                        }
+                    }
+                }
+            }
+        };
+
+        /* *************************************************************
+         * Modals
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function getModals() {
+            return _modalsComponent
+        };
+
+        /**
+         * @public
+         *
+         * @param object formElement
+         * @return void
+         */
+        function showRemoveFormElementModal(formElement) {
+            if (getUtility().isUndefinedOrNull(formElement)) {
+                formElement = getCurrentlySelectedFormElement();
+            }
+            getModals().showRemoveFormElementModal(formElement);
+        };
+
+        /**
+         * @public
+         *
+         * @param string collectionElementIdentifier
+         * @param string collectionName
+         * @param object formElement
+         * @return void
+         */
+        function showRemoveCollectionElementModal(collectionElementIdentifier, collectionName, formElement) {
+            if (getUtility().isUndefinedOrNull(formElement)) {
+                formElement = getCurrentlySelectedFormElement();
+            }
+            getModals().showRemoveCollectionElementModal(collectionElementIdentifier, collectionName, formElement);
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function showCloseConfirmationModal() {
+            getModals().showCloseConfirmationModal();
+        };
+
+        /**
+         * @public
+         *
+         * @param string targetEvent
+         * @return void
+         */
+        function showInsertElementsModal(targetEvent) {
+            getModals().showInsertElementsModal(targetEvent);
+        };
+
+        /**
+         * @public
+         *
+         * @param string targetEvent
+         * @return void
+         */
+        function showInsertPagesModal(targetEvent) {
+            getModals().showInsertPagesModal(targetEvent);
+        };
+
+        /**
+         * @public
+         *
+         * @param bool 
+         * @return void
+         */
+        function showValidationErrorsModal() {
+            var validationResults;
+            validationResults = getFormEditorApp().validateFormElementRecursive(getRootFormElement());
+
+            getModals().showValidationErrorsModal(validationResults);
+        };
+
+        /* *************************************************************
+         * Inspector
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function getInspector() {
+            return _inspectorsComponent
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param bool
+         * @return void
+         */
+        function renderInspectorEditors(formElement, useFadeEffect) {
+            var render;
+            if (getUtility().isUndefinedOrNull(useFadeEffect)) {
+                useFadeEffect = true;
+            }
+
+            /**
+             * @private
+             *
+             * @param function
+             * @return void
+             */
+            render = function(callback) {
+                getInspector().renderEditors(formElement, callback);
+            };
+
+            if (!!useFadeEffect) {
+                getInspector().getInspectorDomElement().fadeOut('fast', function() {
+                    render(function() {
+                        getInspector().getInspectorDomElement().fadeIn('fast');
+                    });
+                });
+            } else {
+                render();
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param string
+         * @param string
+         * @return void
+         */
+        function renderInspectorCollectionElementEditors(collectionName, collectionElementIdentifier) {
+            getInspector().renderCollectionElementEditors(collectionName, collectionElementIdentifier);
+        };
+
+        /**
+         * @public
+         *
+         * @param string content
+         * @return void
+         */
+        function setInspectorFormElementHeaderEditorContent(content) {
+            getInspector().setFormElementHeaderEditorContent(content);
+        };
+
+        /* *************************************************************
+         * Stage
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @return object
+         */
+        function getStage() {
+            return _stageComponent;
+        };
+
+        /**
+         * @public
+         *
+         * @param string title
+         * @return void
+         */
+        function setStageHeadline(title) {
+            getStage().setStageHeadline(title);
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function addStagePanelSelection() {
+            getStage().getStagePanelDomElement().addClass(getHelper().getDomElementClassName('selectedStagePanel'));
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function removeStagePanelSelection() {
+            getStage().getStagePanelDomElement().removeClass(getHelper().getDomElementClassName('selectedStagePanel'));
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function renderPagination() {
+            getStage().renderPagination();
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function renderUndoRedo() {
+            getStage().renderUndoRedo();
+        };
+
+        /**
+         * @public
+         *
+         * @param bool
+         * @param bool
+         * @return void
+         * @publish view/stage/abstract/render/postProcess
+         * @publish view/stage/abstract/render/preProcess
+         */
+        function renderAbstractStageArea(useFadeEffect, toolbarUseFadeEffect) {
+            var render, renderPostProcess;
+
+            $(getHelper().getDomElementDataIdentifierSelector('structureSection'))
+                .animate({
+                    'left': '0px'
+                }, 'slow');
+            $(getHelper().getDomElementDataIdentifierSelector('inspectorSection'))
+                .animate({
+                    'right': '0px'
+                }, 'slow');
+            $(getHelper().getDomElementDataIdentifierSelector('stageContainer'))
+                .animate({
+                    'margin-left': _configuration['panels']['stage']['marginLeft'] + 'px',
+                    'margin-right': _configuration['panels']['stage']['marginRight'] + 'px'
+                }, 'slow');
+
+            if (getUtility().isUndefinedOrNull(useFadeEffect)) {
+                useFadeEffect = true;
+            }
+
+            if (getUtility().isUndefinedOrNull(toolbarUseFadeEffect)) {
+                toolbarUseFadeEffect = true;
+            }
+
+            setButtonActive($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderViewModeAbstract')));
+            removeButtonActive($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderViewModePreview')));
+
+            /**
+             * @private
+             *
+             * @param function
+             * @return void
+             */
+            render = function(callback) {
+                $(getHelper().getDomElementDataIdentifierSelector('stageContainer'))
+                    .addClass(getHelper().getDomElementClassName('stageViewModeAbstract'))
+                    .removeClass(getHelper().getDomElementClassName('stageViewModePreview'));
+
+                getStage().renderAbstractStageArea(undefined, callback);
+            };
+
+            /**
+             * @private
+             *
+             * @return void
+             */
+            renderPostProcess = function() {
+                var formElementTypeDefinition;
+
+                formElementTypeDefinition = getFormElementDefinition(getCurrentlySelectedFormElement());
+                getStage().getAllFormElementDomElements().hover(function() {
+                    getStage().getAllFormElementDomElements().parent().removeClass(getHelper().getDomElementClassName('sortableHover'));
+                    if (
+                        $(this).parent().hasClass(getHelper().getDomElementClassName('formElementIsComposit'))
+                        && !$(this).parent().hasClass(getHelper().getDomElementClassName('formElementIsTopLevel'))
+                    ) {
+                        $(this).parent().addClass(getHelper().getDomElementClassName('sortableHover'));
+                    }
+                });
+
+                showComponent($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderNewPage')));
+                if (
+                    formElementTypeDefinition['_isTopLevelFormElement']
+                    && !formElementTypeDefinition['_isCompositeFormElement']
+                    && !getFormEditorApp().isRootFormElementSelected()
+                ) {
+                    hideComponent($(getHelper().getDomElementDataIdentifierSelector('buttonStageNewElementBottom')));
+                    hideComponent($(getHelper().getDomElementDataIdentifierSelector('stageNewElementRow')));
+                } else {
+                    showComponent($(getHelper().getDomElementDataIdentifierSelector('buttonStageNewElementBottom')));
+                    showComponent($(getHelper().getDomElementDataIdentifierSelector('stageNewElementRow')));
+                }
+
+                refreshSelectedElementItemsBatch(toolbarUseFadeEffect);
+                getPublisherSubscriber().publish('view/stage/abstract/render/postProcess');
+            };
+
+            if (useFadeEffect) {
+                $(getHelper().getDomElementDataIdentifierSelector('stageSection')).fadeOut(400, function() {
+                    render(function() {
+                        getPublisherSubscriber().publish('view/stage/abstract/render/preProcess');
+                        $(getHelper().getDomElementDataIdentifierSelector('stageSection')).fadeIn(400);
+                        renderPostProcess();
+                        getPublisherSubscriber().publish('view/stage/abstract/render/postProcess');
+                    });
+                });
+            } else {
+                render(function() {
+                    getPublisherSubscriber().publish('view/stage/abstract/render/preProcess');
+                    renderPostProcess();
+                    getPublisherSubscriber().publish('view/stage/abstract/render/postProcess');
+                });
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param string html
+         * @return void
+         * @publish view/stage/preview/render/postProcess
+         */
+        function renderPreviewStageArea(html) {
+            $(getHelper().getDomElementDataIdentifierSelector('structureSection'))
+                .animate({
+                    'left': '-=' + _configuration['panels']['structure']['width'] + 'px'
+                }, 'slow');
+            $(getHelper().getDomElementDataIdentifierSelector('inspectorSection'))
+                .animate({
+                    'right': '-=' + _configuration['panels']['inspector']['width'] + 'px'
+                }, 'slow');
+            $(getHelper().getDomElementDataIdentifierSelector('stageContainer'))
+                .animate({
+                    'margin-left': _configuration['panels']['stage']['marginLeftCollapsed'] + 'px',
+                    'margin-right': _configuration['panels']['stage']['marginRightCollapsed'] + 'px'
+                }, 'slow');
+
+            setButtonActive($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderViewModePreview')));
+            removeButtonActive($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderViewModeAbstract')));
+
+            $(getHelper().getDomElementDataIdentifierSelector('stageSection')).fadeOut(400, function() {
+                $(getHelper().getDomElementDataIdentifierSelector('stageContainer'))
+                    .addClass(getHelper().getDomElementClassName('stageViewModePreview'))
+                    .removeClass(getHelper().getDomElementClassName('stageViewModeAbstract'));
+
+                hideComponent($(getHelper().getDomElementDataIdentifierSelector('buttonStageNewElementBottom')));
+                hideComponent($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderNewPage')));
+
+                getStage().renderPreviewStageArea(html);
+                $(getHelper().getDomElementDataIdentifierSelector('stageSection')).fadeIn(400);
+                getPublisherSubscriber().publish('view/stage/preview/render/postProcess');
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function addAbstractViewValidationResults() {
+            var validationResults;
+
+            validationResults = getFormEditorApp().validateFormElementRecursive(getRootFormElement());
+            for (var i = 0, len = validationResults.length; i < len; ++i) {
+                var hasError = false, validationElement;
+                for (var j = 0, len2 = validationResults[i]['validationResults'].length; j < len2; ++j) {
+                    if (
+                        validationResults[i]['validationResults'][j]['validationResults']
+                        && validationResults[i]['validationResults'][j]['validationResults'].length > 0
+                    ) {
+                        hasError = true;
+                        break;
+                    }
+                }
+
+                if (hasError) {
+                    if (i > 0) {
+                        validationElement = getStage().getAbstractViewFormElementDomElement(validationResults[i]['formElementIdentifierPath']);
+                        setElementValidationErrorClass(validationElement);
+                    }
+                }
+            }
+        };
+
+        /* *************************************************************
+         * Form element methods
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @param string formElementType
+         * @param string|object referenceFormElement
+         * @param bool
+         * @return object
+         * @publish view/formElement/inserted
+         */
+        function createAndAddFormElement(formElementType, referenceFormElement, disablePublishersOnSet) {
+            var newFormElement;
+
+            newFormElement = getFormEditorApp().createAndAddFormElement(formElementType, referenceFormElement);
+            if (!!!disablePublishersOnSet) {
+                getPublisherSubscriber().publish('view/formElement/inserted', [newFormElement]);
+            }
+            return newFormElement;
+        };
+
+        /**
+         * @public
+         *
+         * @param string|object formElementToMove
+         * @param string position
+         * @param string|object referenceFormElement
+         * @param bool
+         * @return object
+         * @publish view/formElement/moved
+         */
+        function moveFormElement(formElementToMove, position, referenceFormElement, disablePublishersOnSet) {
+            var movedFormElement;
+
+            movedFormElement = getFormEditorApp().moveFormElement(formElementToMove, position, referenceFormElement, false);
+            if (!!!disablePublishersOnSet) {
+                getPublisherSubscriber().publish('view/formElement/moved', [movedFormElement]);
+            }
+            return movedFormElement;
+        };
+
+        /**
+         * @public
+         *
+         * @param object formElement
+         * @param bool
+         * @return object
+         * @publish view/formElement/removed
+         */
+        function removeFormElement(formElement, disablePublishersOnSet) {
+            var parentFormElement;
+
+            if (getUtility().isUndefinedOrNull(formElement)) {
+                formElement = getCurrentlySelectedFormElement();
+            }
+
+            if (
+                getFormElementDefinition(formElement, '_isTopLevelFormElement')
+                && getFormElementDefinition(formElement, '_isCompositeFormElement')
+                && getRootFormElement().get('renderables').length === 1
+            ) {
+                Notification.error(
+                    getFormElementDefinition(getRootFormElement(), 'modalRemoveElementLastAvailablePageFlashMessageTitle'),
+                    getFormElementDefinition(getRootFormElement(), 'modalRemoveElementLastAvailablePageFlashMessageMessage'),
+                    2
+                );
+            } else {
+                parentFormElement = getFormEditorApp().removeFormElement(formElement, false);
+                if (!!!disablePublishersOnSet) {
+                    getPublisherSubscriber().publish('view/formElement/removed', [parentFormElement]);
+                }
+            }
+            return parentFormElement;
+        };
+
+        /**
+         * @public
+         *
+         * @param string collectionElementIdentifier
+         * @param string collectionName
+         * @param object formElement
+         * @param object collectionElementConfiguration
+         * @param string referenceCollectionElementIdentifier
+         * @param bool
+         * @return void
+         * @publish view/collectionElement/new/added
+         */
+        function createAndAddPropertyCollectionElement(collectionElementIdentifier, collectionName, formElement, collectionElementConfiguration, referenceCollectionElementIdentifier, disablePublishersOnSet) {
+            getFormEditorApp().createAndAddPropertyCollectionElement(
+                collectionElementIdentifier,
+                collectionName,
+                formElement,
+                collectionElementConfiguration,
+                referenceCollectionElementIdentifier
+            );
+            if (!!!disablePublishersOnSet) {
+                getPublisherSubscriber().publish('view/collectionElement/new/added', [
+                    collectionElementIdentifier,
+                    collectionName,
+                    formElement,
+                    collectionElementConfiguration,
+                    referenceCollectionElementIdentifier
+                ]);
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param string collectionElementToMove
+         * @param string position
+         * @param string referenceCollectionElement
+         * @param string collectionName
+         * @param object formElement
+         * @param bool
+         * @return void
+         */
+        function movePropertyCollectionElement(collectionElementToMove, position, referenceCollectionElement, collectionName, formElement, disablePublishersOnSet) {
+            if (getUtility().isUndefinedOrNull(formElement)) {
+                formElement = getCurrentlySelectedFormElement();
+            }
+            getFormEditorApp().movePropertyCollectionElement(
+                collectionElementToMove,
+                position,
+                referenceCollectionElement,
+                collectionName,
+                formElement,
+                false
+            );
+            if (!!!disablePublishersOnSet) {
+                getPublisherSubscriber().publish('view/collectionElement/moved', [
+                    collectionElementToMove,
+                    position,
+                    referenceCollectionElement,
+                    collectionName,
+                    formElement]
+                );
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param string collectionElementIdentifier
+         * @param string collectionName
+         * @param object formElement
+         * @param bool
+         * @return void
+         * @publish view/collectionElement/removed
+         */
+        function removePropertyCollectionElement(collectionElementIdentifier, collectionName, formElement, disablePublishersOnSet) {
+            getFormEditorApp().removePropertyCollectionElement(collectionElementIdentifier, collectionName, formElement);
+            if (!!!disablePublishersOnSet) {
+                getPublisherSubscriber().publish('view/collectionElement/removed', [
+                    collectionElementIdentifier,
+                    collectionName,
+                    formElement]
+                );
+            }
+        };
+
+        /* *************************************************************
+         * Batch methodes
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @param bool
+         * @return void
+         */
+        function refreshSelectedElementItemsBatch(toolbarUseFadeEffect) {
+            var formElementTypeDefinition, selectedElement;
+
+            if (getUtility().isUndefinedOrNull(toolbarUseFadeEffect)) {
+                toolbarUseFadeEffect = true;
+            }
+
+            formElementTypeDefinition = getFormElementDefinition(getCurrentlySelectedFormElement());
+
+            getStage().removeAllStageToolbars();
+            removeAllStageElementSelectionsBatch();
+            removeAllStructureSelections();
+
+            if (!getFormEditorApp().isRootFormElementSelected()) {
+                removeStructureRootElementSelection();
+                addStructureSelection();
+
+                selectedElement = getStage().getAbstractViewFormElementDomElement();
+
+                if (formElementTypeDefinition['_isTopLevelFormElement']) {
+                    addStagePanelSelection();
+                } else {
+                    selectedElement.addClass(getHelper().getDomElementClassName('selectedFormElement'));
+                    getStage().createAndAddAbstractViewFormElementToolbar(selectedElement, undefined, toolbarUseFadeEffect);
+                }
+
+                getStage().getAllFormElementDomElements().parent().removeClass(getHelper().getDomElementClassName('selectedCompositFormElement'));
+                if (!formElementTypeDefinition['_isTopLevelFormElement'] && formElementTypeDefinition['_isCompositeFormElement']) {
+                    selectedElement.parent().addClass(getHelper().getDomElementClassName('selectedCompositFormElement'));
+                }
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param int
+         * @return void
+         * @throws 1478651732
+         * @throws 1478651733
+         * @throws 1478651734
+         */
+        function selectPageBatch(pageIndex) {
+            assert('number' === $.type(pageIndex), 'Invalid parameter "pageIndex"', 1478651732);
+            assert(pageIndex >= 0, 'Invalid parameter "pageIndex"', 1478651733);
+            assert(pageIndex < getRootFormElement().get('renderables').length, 'Invalid parameter "pageIndex"', 1478651734);
+
+            getFormEditorApp().setCurrentlySelectedFormElement(getRootFormElement().get('renderables')[pageIndex]);
+            renewStructure();
+            renderPagination()
+            refreshSelectedElementItemsBatch();
+            renderInspectorEditors();
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function removeAllStageElementSelectionsBatch() {
+            getStage().getAllFormElementDomElements().removeClass(getHelper().getDomElementClassName('selectedFormElement'));
+            removeStagePanelSelection();
+            getStage().getAllFormElementDomElements().parent().removeClass(getHelper().getDomElementClassName('sortableHover'));        
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function onViewReadyBatch() {
+            $(getHelper().getDomElementDataIdentifierSelector('structureSection'))
+                .css({
+                    width: _configuration['panels']['structure']['width'] + 'px',
+                    left: '-=' + _configuration['panels']['structure']['width'] + 'px'
+                });
+            $(getHelper().getDomElementDataIdentifierSelector('inspectorSection'))
+                .css({
+                    width: _configuration['panels']['inspector']['width'] + 'px',
+                    right: '-=' + _configuration['panels']['inspector']['width'] + 'px'
+                });
+
+            $(getHelper().getDomElementClassName('headerButtonBar', true))
+                .css({
+                    'margin-left': _configuration['panels']['structure']['width'] + 'px'
+                });
+
+            $(getHelper().getDomElementDataIdentifierSelector('stageContainer'))
+                .css({
+                    'margin-left': _configuration['panels']['stage']['marginLeft'] + 'px',
+                    'margin-right': _configuration['panels']['stage']['marginRight'] + 'px'
+                });
+
+            hideComponent($(getHelper().getDomElementDataIdentifierSelector('buttonStageNewElementBottom')));
+            hideComponent($(getHelper().getDomElementDataIdentifierSelector('stageNewElementRow')));
+
+            setStageHeadline();
+            setStructureRootElementTitle();
+            renderAbstractStageArea(false);
+            renewStructure();
+            addStructureRootElementSelection();
+            renderInspectorEditors();
+            renderPagination();
+
+            hideComponent($(getHelper().getDomElementDataIdentifierSelector('moduleLoadingIndicator')));
+            showComponent($(getHelper().getDomElementDataIdentifierSelector('moduleWrapper')));
+            showComponent($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderSave')));
+            showComponent($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderClose')));
+            showComponent($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderNewPage')));
+            showComponent($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderUndo')));
+            showComponent($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderRedo')));
+            setButtonActive($(getHelper().getDomElementDataIdentifierSelector('buttonHeaderViewModeAbstract')));
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param object
+         * @return void
+         */
+        function onAbstractViewDndStartBatch(draggedFormElementDomElement, draggedFormPlaceholderDomElement) {
+            draggedFormPlaceholderDomElement.removeClass(getHelper().getDomElementClassName('sortableHover'));
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param string
+         * @param object
+         * @return void
+         */
+        function onAbstractViewDndChangeBatch(placeholderDomElement, parentFormElementIdentifierPath, enclosingCompositeFormElement) {
+            getStage().getAllFormElementDomElements().parent().removeClass(getHelper().getDomElementClassName('sortableHover'));
+            if (enclosingCompositeFormElement) {
+                getStage().getAbstractViewParentFormElementWithinDomElement(placeholderDomElement).parent().addClass(getHelper().getDomElementClassName('sortableHover'));
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param string
+         * @param string
+         * @param string
+         * @return void
+         * @throws 1472502237
+         */
+        function onAbstractViewDndUpdateBatch(movedDomElement, movedFormElementIdentifierPath, previousFormElementIdentifierPath, nextFormElementIdentifierPath) {
+            var movedFormElement, parentFormElementIdentifierPath;
+            if (nextFormElementIdentifierPath) {
+                movedFormElement = moveFormElement(movedFormElementIdentifierPath, 'before', nextFormElementIdentifierPath);
+            } else if (previousFormElementIdentifierPath) {
+                movedFormElement = moveFormElement(movedFormElementIdentifierPath, 'after', previousFormElementIdentifierPath);
+            } else {
+                parentFormElementIdentifierPath = getStage().getAbstractViewParentFormElementIdentifierPathWithinDomElement(movedDomElement);
+                if (parentFormElementIdentifierPath) {
+                    movedFormElement = moveFormElement(movedFormElementIdentifierPath, 'inside', parentFormElementIdentifierPath);
+                } else {
+                    assert(false, 'Next element, previous or parent element need to be set.', 1472502237);
+                }
+            }
+
+            getStage()
+                .getAbstractViewFormElementWithinDomElement(movedDomElement)
+                .attr(
+                    getHelper().getDomElementDataAttribute('elementIdentifier'),
+                    movedFormElement.get('__identifierPath')
+                );
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param string
+         * @param object
+         * @return void
+         */
+        function onStructureDndChangeBatch(placeholderDomElement, parentFormElementIdentifierPath, enclosingCompositeFormElement) {
+            getStructure()
+                .getAllTreeNodes()
+                .parent()
+                .removeClass(getHelper().getDomElementClassName('sortableHover'));
+
+            getStage()
+                .getAllFormElementDomElements()
+                .parent()
+                .removeClass(getHelper().getDomElementClassName('sortableHover'));
+
+            if (enclosingCompositeFormElement) {
+                getStructure()
+                    .getParentTreeNodeWithinDomElement(placeholderDomElement)
+                    .parent()
+                    .addClass(getHelper().getDomElementClassName('sortableHover'));
+
+                getStage()
+                    .getAbstractViewFormElementDomElement(enclosingCompositeFormElement)
+                    .parent()
+                    .addClass(getHelper().getDomElementClassName('sortableHover'));
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param string
+         * @param string
+         * @param string
+         * @return void
+         * @throws 1479048646
+         */
+        function onStructureDndUpdateBatch(movedDomElement, movedFormElementIdentifierPath, previousFormElementIdentifierPath, nextFormElementIdentifierPath) {
+            var movedFormElement, parentFormElementIdentifierPath;
+            if (nextFormElementIdentifierPath) {
+                movedFormElement = moveFormElement(movedFormElementIdentifierPath, 'before', nextFormElementIdentifierPath);
+            } else if (previousFormElementIdentifierPath) {
+                movedFormElement = moveFormElement(movedFormElementIdentifierPath, 'after', previousFormElementIdentifierPath);
+            } else {
+                parentFormElementIdentifierPath = getStructure().getParentTreeNodeIdentifierPathWithinDomElement(movedDomElement);
+                if (parentFormElementIdentifierPath) {
+                    movedFormElement = moveFormElement(movedFormElementIdentifierPath, 'inside', parentFormElementIdentifierPath);
+                } else {
+                    getFormEditorApp().assert(false, 'Next element, previous or parent element need to be set.', 1479048646);
+                }
+            }
+
+            getStructure()
+                .getTreeNodeWithinDomElement(movedDomElement)
+                .attr(
+                    getHelper().getDomElementDataAttribute('elementIdentifier'),
+                    movedFormElement.get('__identifierPath')
+                );
+        };
+
+        /* *************************************************************
+         * Misc
+         * ************************************************************/
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function closeEditor() {
+            document.location.href = $(getHelper().getDomElementDataIdentifierSelector('buttonHeaderClose')).prop('href');
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param string
+         * @return void
+         */
+        function setElementValidationErrorClass(element, classIdentifier) {
+            if (getFormEditorApp().getUtility().isUndefinedOrNull(classIdentifier)) {
+                element.addClass(getHelper().getDomElementClassName('validationErrors'));
+            } else {
+                element.addClass(getHelper().getDomElementClassName(classIdentifier));
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @param string
+         * @return void
+         */
+        function removeElementValidationErrorClass(element, classIdentifier) {
+            if (getFormEditorApp().getUtility().isUndefinedOrNull(classIdentifier)) {
+                element.removeClass(getHelper().getDomElementClassName('validationErrors'));
+            } else {
+                element.removeClass(getHelper().getDomElementClassName(classIdentifier));
+            }
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return void
+         */
+        function showComponent(element) {
+            element.removeClass(getHelper().getDomElementClassName('hidden')).show();
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return void
+         */
+        function hideComponent(element) {
+            element.addClass(getHelper().getDomElementClassName('hidden')).hide();
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return void
+         */
+        function enableButton(buttonElement) {
+            buttonElement.prop('disabled', false).removeClass(getHelper().getDomElementClassName('disabled'));
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return void
+         */
+        function disableButton(buttonElement) {
+            buttonElement.prop('disabled', 'disabled').addClass(getHelper().getDomElementClassName('disabled'));
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return void
+         */
+        function setButtonActive(buttonElement) {
+            buttonElement.addClass(getHelper().getDomElementClassName('active'));
+        };
+
+        /**
+         * @public
+         *
+         * @param object
+         * @return void
+         */
+        function removeButtonActive(buttonElement) {
+            buttonElement.removeClass(getHelper().getDomElementClassName('active'));
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function showSaveButtonSpinnerIcon() {
+            Icons.getIcon(getHelper().getDomElementDataAttributeValue('iconSaveSpinner'), Icons.sizes.small).done(function(markup) {
+                $(getHelper().getDomElementDataIdentifierSelector('iconSave')).replaceWith($(markup));
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function showSaveButtonSaveIcon() {
+            Icons.getIcon(getHelper().getDomElementDataAttributeValue('iconSave'), Icons.sizes.small).done(function(markup) {
+                $(getHelper().getDomElementDataIdentifierSelector('iconSaveSpinner')).replaceWith($(markup));
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @return void
+         */
+        function showSaveSuccessMessage() {
+            Notification.success(
+                getFormElementDefinition(getRootFormElement(), 'saveSuccessFlashMessageTitle'),
+                getFormElementDefinition(getRootFormElement(), 'saveSuccessFlashMessageMessage'),
+                2
+            );
+        };
+
+        /**
+         * @public
+         *
+         * @param string
+         * @param string
+         * @return void
+         */
+        function showErrorFlashMessage(title, message) {
+            Notification.error(title, message, 2);
+        };
+
+        /**
+         * @public
+         *
+         * @param object formEditorApp
+         * @param object additionalViewModelModules
+         * @return void
+         */
+        function bootstrap(formEditorApp, additionalViewModelModules) {
+            _formEditorApp = formEditorApp;
+
+            _helperSetup();
+            _structureComponentSetup();
+            _modalsComponentSetup();
+            _inspectorsComponentSetup();
+            _stageComponentSetup();
+            _buttonsSetup();
+            _addPropertyValidators();
+            _loadAdditionalModules(additionalViewModelModules);
+        };
+
+        /**
+         * Publish the public methods.
+         * Implements the "Revealing Module Pattern".
+         */
+        return {
+            addAbstractViewValidationResults: addAbstractViewValidationResults,
+            addStagePanelSelection: addStagePanelSelection,
+            addStructureRootElementSelection: addStructureRootElementSelection,
+            addStructureSelection: addStructureSelection,
+            addStructureValidationResults: addStructureValidationResults,
+            bootstrap: bootstrap,
+            closeEditor: closeEditor,
+            createAndAddFormElement: createAndAddFormElement,
+            createAndAddPropertyCollectionElement: createAndAddPropertyCollectionElement,
+            disableButton: disableButton,
+            enableButton: enableButton,
+            getConfiguration: getConfiguration,
+            getFormEditorApp: getFormEditorApp,
+            getFormElementDefinition: getFormElementDefinition,
+            getHelper: getHelper,
+            getInspector: getInspector,
+            getModals: getModals,
+            getPreviewMode: getPreviewMode,
+            getStage: getStage,
+            getStructure: getStructure,
+            getStructureRootElement: getStructureRootElement,
+            hideComponent: hideComponent,
+            moveFormElement: moveFormElement,
+            movePropertyCollectionElement: movePropertyCollectionElement,
+            onAbstractViewDndChangeBatch: onAbstractViewDndChangeBatch,
+            onAbstractViewDndStartBatch: onAbstractViewDndStartBatch,
+            onAbstractViewDndUpdateBatch: onAbstractViewDndUpdateBatch,
+            onStructureDndChangeBatch: onStructureDndChangeBatch,
+            onStructureDndUpdateBatch: onStructureDndUpdateBatch,
+            onViewReadyBatch: onViewReadyBatch,
+            refreshSelectedElementItemsBatch: refreshSelectedElementItemsBatch,
+            removeAllStageElementSelectionsBatch: removeAllStageElementSelectionsBatch,
+            removeAllStructureSelections: removeAllStructureSelections,
+            removeButtonActive: removeButtonActive,
+            removeElementValidationErrorClass: removeElementValidationErrorClass,
+            removeFormElement: removeFormElement,
+            removePropertyCollectionElement: removePropertyCollectionElement,
+            removeStagePanelSelection: removeStagePanelSelection,
+            removeStructureRootElementSelection: removeStructureRootElementSelection,
+            removeStructureSelection: removeStructureSelection,
+            renderAbstractStageArea: renderAbstractStageArea,
+            renderInspectorEditors: renderInspectorEditors,
+            renderInspectorCollectionElementEditors: renderInspectorCollectionElementEditors,
+            renderPagination: renderPagination,
+            renderPreviewStageArea: renderPreviewStageArea,
+            renewStructure: renewStructure,
+            renderUndoRedo: renderUndoRedo,
+            selectPageBatch: selectPageBatch,
+            setButtonActive: setButtonActive,
+            setElementValidationErrorClass: setElementValidationErrorClass,
+            setInspectorFormElementHeaderEditorContent: setInspectorFormElementHeaderEditorContent,
+            setPreviewMode: setPreviewMode,
+            setStageHeadline: setStageHeadline,
+            setStructureRootElementTitle: setStructureRootElementTitle,
+            showCloseConfirmationModal: showCloseConfirmationModal,
+            showComponent: showComponent,
+            showErrorFlashMessage: showErrorFlashMessage,
+            showInsertElementsModal: showInsertElementsModal,
+            showInsertPagesModal: showInsertPagesModal,
+            showRemoveFormElementModal: showRemoveFormElementModal,
+            showRemoveCollectionElementModal: showRemoveCollectionElementModal,
+            showSaveButtonSaveIcon: showSaveButtonSaveIcon,
+            showSaveButtonSpinnerIcon: showSaveButtonSpinnerIcon,
+            showSaveSuccessMessage: showSaveSuccessMessage,
+            showValidationErrorsModal: showValidationErrorsModal
+        };
+    })($, TreeComponent, ModalsComponent, InspectorComponent, StageComponent, Helper, Icons, Notification);
+});
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormManager.js b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormManager.js
new file mode 100644
index 0000000000000000000000000000000000000000..26a70aa1941dd521be5e894be5344c2a42f82649
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormManager.js
@@ -0,0 +1,240 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/Form/Backend/FormManager
+ */
+define(['jquery'], function($) {
+        'use strict';
+
+    /**
+     * Return a static method named "getInstance".
+     * Use this method to create the formmanager app.
+     */
+    return (function() {
+
+        /**
+         * @private
+         *
+         * Hold the instance (Singleton Pattern)
+         */
+        var _formManagerInstance = null;
+
+        /**
+         * @public
+         *
+         * @param object _configuration
+         * @param object _viewModel
+         * @return object
+         */
+        function FormManager(_configuration, _viewModel) {
+
+            /**
+             * @private
+             *
+             * @var bool
+             */
+            var _isRunning = false;
+
+            /**
+             * @public
+             *
+             * @param mixed test
+             * @param string message
+             * @param int messageCode
+             * @return void
+             */
+            function assert(test, message, messageCode) {
+                if ('function' === $.type(test)) {
+                    test = (test() !== false);
+                }
+                if (!test) {
+                    message = message || "Assertion failed";
+                    if (messageCode) {
+                        message = message + ' (' + messageCode + ')';
+                    }
+                    if ('undefined' !== typeof Error) {
+                        throw new Error(message);
+                    }
+                    throw message;
+                }
+            };
+
+            /**
+             * @private
+             *
+             * @var bool
+             */
+            var _isRunning = false;
+
+            /**
+             * @public
+             *
+             * @return object
+             */
+            function getPrototypes() {
+                var prototypes = [];
+
+                if ('array' === $.type(_configuration['selectablePrototypesConfiguration'])) {
+                    for (var i = 0, len = _configuration['selectablePrototypesConfiguration'].length; i < len; ++i) {
+                        prototypes.push({
+                            label: _configuration['selectablePrototypesConfiguration'][i]['label'],
+                            value: _configuration['selectablePrototypesConfiguration'][i]['identifier'],
+                        });
+                    }
+                }
+                return prototypes;
+            };
+
+            /**
+             * @public
+             *
+             * @param string prototypeName
+             * @return object
+             */
+            function getTemplatesForPrototype(prototypeName) {
+                var templates = [];
+                assert('string' === $.type(prototypeName), 'Invalid parameter "prototypeName"', 1475945286);
+                if ('array' === $.type(_configuration['selectablePrototypesConfiguration'])) {
+                    for (var i = 0, len1 = _configuration['selectablePrototypesConfiguration'].length; i < len1; ++i) {
+                        if (_configuration['selectablePrototypesConfiguration'][i]['identifier'] !== prototypeName) {
+                            continue;
+                        }
+                        if ('array' === $.type(_configuration['selectablePrototypesConfiguration'][i]['newFormTemplates'])) {
+                            for (var j = 0, len2 = _configuration['selectablePrototypesConfiguration'][i]['newFormTemplates'].length; j < len2; ++j) {
+                                templates.push({
+                                    label: _configuration['selectablePrototypesConfiguration'][i]['newFormTemplates'][j]['label'],
+                                    value: _configuration['selectablePrototypesConfiguration'][i]['newFormTemplates'][j]['templatePath'],
+                                });
+                            }
+                        }
+                    }
+                }
+
+                return templates;
+            };
+
+            /**
+             * @public
+             *
+             * @param string prototypeName
+             * @return object
+             */
+            function getAccessibleFormStorageFolders() {
+                var folders = [];
+
+                if ('array' === $.type(_configuration['accessibleFormStorageFolders'])) {
+                    for (var i = 0, len1 = _configuration['accessibleFormStorageFolders'].length; i < len1; ++i) {
+                        folders.push({
+                            label: _configuration['accessibleFormStorageFolders'][i]['label'],
+                            value: _configuration['accessibleFormStorageFolders'][i]['value'],
+                        });
+                    }
+                }
+                return folders;
+            };
+
+            /**
+             * @public
+             *
+             * @param string prototypeName
+             * @return object
+             * @throws 1477506508
+             */
+            function getAjaxEndpoint(endpointName) {
+                var templates = [];
+                assert(typeof _configuration['endpoints'][endpointName] !== 'undefined', 'Endpoint ' + endpointName + ' does not exist', 1477506508);
+
+                return _configuration['endpoints'][endpointName];
+            };
+
+            /**
+             * @private
+             *
+             * @return void
+             * @throws 1475942906
+             */
+            function _viewSetup() {
+                assert('function' === $.type(_viewModel.bootstrap), 'The view model does not implement the method "bootstrap"', 1475942906);
+                _viewModel.bootstrap(_formManagerInstance);
+            };
+
+            /**
+             * @private
+             *
+             * @return void
+             * @throws 1477506504
+             */
+            function _bootstrap() {
+                _configuration = _configuration || {};
+                assert('object' === $.type(_configuration['endpoints']), 'Invalid parameter "endpoints"', 1477506504);
+                _viewSetup();
+            };
+
+            /**
+             * @public
+             *
+             * @return TYPO3/CMS/Form/Backend/FormManager
+             * @throws 1475942618
+             */
+            function run() {
+                if (_isRunning) {
+                    throw 'You can not run the app twice (1475942618)';
+                }
+
+                _bootstrap();
+                _isRunning = true;
+                return this;
+            };
+
+            /**
+             * Publish the public methods.
+             * Implements the "Revealing Module Pattern".
+             */
+            return {
+                getPrototypes: getPrototypes,
+                getTemplatesForPrototype: getTemplatesForPrototype,
+                getAccessibleFormStorageFolders: getAccessibleFormStorageFolders,
+                getAjaxEndpoint: getAjaxEndpoint,
+
+                assert: assert,
+                run: run
+            };
+        };
+
+        /**
+         * Emulation of static methods
+         */
+        return {
+            /**
+             * @public
+             * @static
+             *
+             * Implement the "Singleton Pattern".
+             *
+             * Return a singleton instance of a
+             * "FormManager" object.
+             *
+             * @param object configuration
+             * @param object viewModel
+             * @return object
+             */
+            getInstance: function(configuration, viewModel) {
+                if(_formManagerInstance === null) {
+                    _formManagerInstance = new FormManager(configuration, viewModel);
+                }
+                return _formManagerInstance;
+            }
+        };
+    })();
+});
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormManager/ViewModel.js b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormManager/ViewModel.js
new file mode 100644
index 0000000000000000000000000000000000000000..d379fe6ecb0fed2880d45cff98163832a200ef27
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/JavaScript/Backend/FormManager/ViewModel.js
@@ -0,0 +1,534 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/Form/Backend/FormManager/ViewModel
+ */
+define(['jquery',
+        'TYPO3/CMS/Backend/Modal',
+        'TYPO3/CMS/Backend/Severity',
+        'TYPO3/CMS/Backend/Wizard',
+        'TYPO3/CMS/Backend/Icons',
+        'TYPO3/CMS/Backend/Notification'
+        ], function($, Modal, Severity, Wizard, Icons, Notification) {
+        'use strict';
+
+    return (function($, Modal, Severity, Wizard, Icons,Notification) {
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _formManagerApp = null;
+
+        /**
+         * @private
+         *
+         * @var object
+         */
+        var _domElementIdentifierCache = {};
+
+        /**
+         * @private
+         *
+         * @return void
+         */
+        function _domElementIdentifierCacheSetup() {
+            _domElementIdentifierCache = {
+                newFormModalTrigger: { identifier: '[data-identifier="newForm"]' },
+                duplicateFormModalTrigger: { identifier: '[data-identifier="duplicateForm"]' },
+                removeFormModalTrigger: { identifier: '[data-identifier="removeForm"]' },
+
+                newFormName: { identifier: '[data-identifier="newFormName"]' },
+                newFormSavePath: { identifier: '[data-identifier="newFormSavePath"]' },
+                advancedWizard: { identifier: '[data-identifier="advancedWizard"]' },
+                newFormPrototypeName: { identifier: '[data-identifier="newFormPrototypeName"]' },
+                newFormTemplate: { identifier: '[data-identifier="newFormTemplate"]' },
+
+                duplicateFormName: { identifier: '[data-identifier="duplicateFormName"]' },
+                duplicateFormSavePath: { identifier: '[data-identifier="duplicateFormSavePath"]' },
+
+                showReferences: { identifier: '[data-identifier="showReferences"]' },
+                referenceLink: { identifier: '[data-identifier="referenceLink"]' },
+
+                tooltip: { identifier: '[data-toggle="tooltip"]' }
+            }
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         * @throws 1477506500
+         * @throws 1477506501
+         * @throws 1477506502
+         */
+        function _newFormSetup() {
+            $(getDomElementIdentifier('newFormModalTrigger')).on('click', function(e) {
+                e.preventDefault();
+
+                /**
+                 * Wizard step 1
+                 */
+                Wizard.addSlide('new-form-step-1', TYPO3.lang['formManager.newFormWizard.step1.title'], '', Severity.info, function(slide) {
+                    var advandecWizardHasOptions, folders, html, modal, nextButton, prototypes, savePathSelect, templates;
+
+                    modal = Wizard.setup.$carousel.closest('.modal');
+                    nextButton = modal.find('.modal-footer').find('button[name="next"]');
+
+                    folders = _formManagerApp.getAccessibleFormStorageFolders();
+                    _formManagerApp.assert(folders.length > 0, 'No accessible form storage folders', 1477506500);
+
+                    Wizard.set('savePath', folders[0]['value']);
+                    if (folders.length > 1) {
+                        savePathSelect = $('<select class="new-form-save-path form-control" data-identifier="newFormSavePath" />');
+                        for (var i = 0, len = folders.length; i < len; ++i) {
+                            var option = new Option(folders[i]['label'], folders[i]['value']);
+                            $(savePathSelect).append(option);
+                        }
+                    }
+
+                    prototypes = _formManagerApp.getPrototypes();
+
+                    _formManagerApp.assert(prototypes.length > 0, 'No prototypes available', 1477506501);
+                    Wizard.set('prototypeName', prototypes[0]['value']);
+
+                    templates = _formManagerApp.getTemplatesForPrototype(prototypes[0]['value']);
+                    _formManagerApp.assert(templates.length > 0, 'No templates available', 1477506502);
+                    Wizard.set('templatePath', templates[0]['value']);
+
+                    html = '<div class="new-form-modal">'
+                             + '<div class="form-horizontal">'
+                                 + '<div>'
+                                     + '<label class="control-label">' + TYPO3.lang['formManager.form_name'] + '</label>'
+                                     + '<input class="new-form-name form-control has-error" data-identifier="newFormName" />';
+
+                    if (savePathSelect) {
+                        html +=        '<label class="control-label">' + TYPO3.lang['formManager.form_save_path'] + '</label>' + $(savePathSelect)[0].outerHTML;
+                    }
+
+                    if (prototypes.length > 1 || templates.length > 1) {
+                        html +=        '<label class="control-label">' + TYPO3.lang['formManager.newFormWizard.step1.advanced'] + '</label>'
+                                     + '<div class="t3-form-controls"><input type="checkbox" class="new-form-advance-wizard" data-identifier="advancedWizard" /></div>';
+                    }
+
+                    html +=        '</div>'
+                             + '</div>'
+                         + '</div>';
+
+                    slide.html(html);
+                    $(getDomElementIdentifier('newFormName'), modal).focus();
+
+                    $(getDomElementIdentifier('newFormName'), modal).on('keyup paste', function(e) {
+                        if ($(this).val().length > 0) {
+                            $(this).removeClass('has-error');
+                            Wizard.unlockNextStep();
+                            Wizard.set('formName', $(this).val());
+                        } else {
+                            $(this).addClass('has-error');
+                            Wizard.lockNextStep();
+                        }
+                    });
+
+                    $(getDomElementIdentifier('newFormSavePath'), modal).on('change', function(e) {
+                        Wizard.set('savePath', $(getDomElementIdentifier('newFormSavePath') + ' option:selected', modal).val());
+                    });
+
+                    $(getDomElementIdentifier('advancedWizard'), modal).on('change', function(e) {
+                        if ($(this).is(':checked')) {
+                            Wizard.set('advancedWizard', true);
+                        } else {
+                            Wizard.set('advancedWizard', false);
+                        }
+                    });
+
+                    nextButton.on('click', function() {
+                        Wizard.setup.forceSelection = false;
+                        Icons.getIcon('spinner-circle-dark', Icons.sizes.large, null, null).done(function(markup) {
+                            slide.html($('<div />', {class: 'text-center'}).append(markup));
+                        });
+                    });
+                });
+
+                /**
+                 * Wizard step 2
+                 */
+                Wizard.addSlide('new-form-step-2', TYPO3.lang['formManager.newFormWizard.step2.title'], '', Severity.info, function(slide, settings) {
+                    var addOnTemplateChangeEvents, html, modal, nextButton, prototypes, prototypeNameSelect, templates, templateSelect;
+
+                    if (settings['advancedWizard'] !== true) {
+                        Wizard.unlockNextStep().trigger('click');
+                        return;
+                    }
+
+                    modal = Wizard.setup.$carousel.closest('.modal');
+                    nextButton = modal.find('.modal-footer').find('button[name="next"]');
+
+                    prototypeNameSelect = $('<select class="new-form-prototype-name form-control" data-identifier="newFormPrototypeName" />');
+                    templateSelect = $('<select class="new-form-template form-control" data-identifier="newFormTemplate" />');
+
+                    prototypes = _formManagerApp.getPrototypes();
+                    templates = {};
+                    if (prototypes.length > 0) {
+                        for (var i = 0, len = prototypes.length; i < len; ++i) {
+                            var option = new Option(prototypes[i]['label'], prototypes[i]['value']);
+                            $(prototypeNameSelect).append(option);
+                        }
+
+                        templates = _formManagerApp.getTemplatesForPrototype(prototypes[0]['value']);
+                        for (var i = 0, len = templates.length; i < len; ++i) {
+                            var option = new Option(templates[i]['label'], templates[i]['value']);
+                            $(templateSelect).append(option);
+                        }
+                    }
+
+                    html = '<div class="new-form-modal">'
+                             + '<div class="form-horizontal">'
+                                 + '<div>';
+
+                    if (prototypes.length > 1) {
+                        html +=        '<label class="control-label">' + TYPO3.lang['formManager.form_prototype'] + '</label>' + $(prototypeNameSelect)[0].outerHTML;
+                    }
+                    if (templates.length > 1) {
+                        html +=        '<label class="control-label">' + TYPO3.lang['formManager.form_template'] + '</label>' + $(templateSelect)[0].outerHTML;
+                    }
+
+                    html +=        '</div>'
+                             + '</div>'
+                         + '</div>';
+
+                    slide.html(html);
+                    if (prototypes.length > 1) {
+                        $(getDomElementIdentifier('newFormPrototypeName'), modal).focus();
+                    } else if (templates.length > 1) {
+                        $(getDomElementIdentifier('newFormTemplate'), modal).focus();
+                    }
+
+                    addOnTemplateChangeEvents = function() {
+                        $(getDomElementIdentifier('newFormTemplate'), modal).on('change', function(e) {
+                            Wizard.set('templatePath', $(getDomElementIdentifier('newFormTemplate') + ' option:selected', modal).val());
+                        });
+                    };
+
+                    $(getDomElementIdentifier('newFormPrototypeName'), modal).on('change', function(e) {
+                        Wizard.set('prototypeName', $(this).val());
+                        templates = _formManagerApp.getTemplatesForPrototype($(this).val());
+                        $(getDomElementIdentifier('newFormTemplate'), modal).off().empty();
+                        for (var i = 0, len = templates.length; i < len; ++i) {
+                            var option = new Option(templates[i]['label'], templates[i]['value']);
+                            $(getDomElementIdentifier('newFormTemplate'), modal).append(option);
+                            Wizard.set('templatePath', templates[0]['value']);
+                        }
+                        addOnTemplateChangeEvents();
+                    });
+
+                    addOnTemplateChangeEvents();
+
+                    nextButton.on('click', function() {
+                        Icons.getIcon('spinner-circle-dark', Icons.sizes.large, null, null).done(function(markup) {
+                            slide.html($('<div />', {class: 'text-center'}).append(markup));
+                        });
+                    });
+                });
+
+                /**
+                 * Wizard step 3
+                 */
+                Wizard.addSlide('new-form-step-3', TYPO3.lang['formManager.newFormWizard.step3.title'], TYPO3.lang['formManager.newFormWizard.step3.message'], Severity.info);
+
+                /**
+                 * Wizard step 4
+                 */
+                Wizard.addFinalProcessingSlide(function() {
+                    $.post(_formManagerApp.getAjaxEndpoint('create'), {
+                        tx_form_web_formformbuilder: {
+                            formName: Wizard.setup.settings['formName'],
+                            templatePath: Wizard.setup.settings['templatePath'],
+                            prototypeName: Wizard.setup.settings['prototypeName'],
+                            savePath: Wizard.setup.settings['savePath']
+                        }
+                    }, function(data, textStatus, jqXHR) {
+                        document.location = data;
+                        Wizard.dismiss();
+                    }).fail(function(jqXHR, textStatus, errorThrown) {
+                        Notification.error(textStatus, errorThrown, 2);
+                        Wizard.dismiss();
+                    });
+                }).done(function() {
+                    Wizard.show();
+                });
+            });
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         */
+        function _removeFormSetup() {
+            $(getDomElementIdentifier('removeFormModalTrigger')).on('click', function(e) {
+                var modalButtons = [], that;
+
+                e.preventDefault();
+                that = $(this)
+
+                modalButtons.push({
+                    text: TYPO3.lang['formManager.cancel'],
+                    active: true,
+                    btnClass: 'btn-default',
+                    name: 'cancel',
+                    trigger: function () {
+                        Modal.currentModal.trigger('modal-dismiss');
+                    }
+                });
+
+                modalButtons.push({
+                    text: TYPO3.lang['formManager.remove_form'],
+                    active: true,
+                    btnClass: 'btn-warning',
+                    name: 'createform',
+                    trigger: function () {
+                        document.location = _formManagerApp.getAjaxEndpoint('delete') + '&tx_form_web_formformbuilder[formPersistenceIdentifier]=' + that.data('formPersistenceIdentifier');
+                        Modal.currentModal.trigger('modal-dismiss');
+                    }
+                });
+
+                Modal.show(
+                    TYPO3.lang['formManager.remove_form_title'],
+                    TYPO3.lang['formManager.remove_form_message'],
+                    Severity.warning,
+                    modalButtons
+                );
+            });
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         * @throws 1477649539
+         */
+        function _duplicateFormSetup() {
+            $(getDomElementIdentifier('duplicateFormModalTrigger')).on('click', function(e) {
+                var that;
+
+                e.preventDefault();
+                that = $(this);
+
+                /**
+                 * Wizard step 1
+                 */
+                Wizard.addSlide('duplicate-form-step-1', TYPO3.lang['formManager.duplicateFormWizard.step1.title'].replace('{0}', that.data('formName')), '', Severity.info, function(slide) {
+                    var folders, html, modal, nextButton, savePathSelect;
+
+                    modal = Wizard.setup.$carousel.closest('.modal');
+                    nextButton = modal.find('.modal-footer').find('button[name="next"]');
+
+                    folders = _formManagerApp.getAccessibleFormStorageFolders();
+                    _formManagerApp.assert(folders.length > 0, 'No accessible form storage folders', 1477649539);
+
+                    Wizard.set('formPersistenceIdentifier', that.data('formPersistenceIdentifier'));
+                    Wizard.set('savePath', folders[0]['value']);
+                    if (folders.length > 1) {
+                        savePathSelect = $('<select class="duplicate-form-save-path form-control" data-identifier="duplicateFormSavePath" />');
+                        for (var i = 0, len = folders.length; i < len; ++i) {
+                            var option = new Option(folders[i]['label'], folders[i]['value']);
+                            $(savePathSelect).append(option);
+                        }
+                    }
+
+                    html = '<div class="duplicate-form-modal">'
+                             + '<div class="form-horizontal">'
+                                 + '<div>'
+                                     + '<label class="control-label">' + TYPO3.lang['formManager.new_form_name'] + '</label>'
+                                     + '<input class="duplicate-form-name form-control has-error" data-identifier="duplicateFormName" />';
+
+                    if (savePathSelect) {
+                        html +=        '<label class="control-label">' + TYPO3.lang['formManager.form_save_path'] + '</label>' + $(savePathSelect)[0].outerHTML;
+                    }
+
+                    html +=        '</div>'
+                             + '</div>'
+                         + '</div>';
+
+                    slide.html(html);
+                    $(getDomElementIdentifier('duplicateFormName'), modal).focus();
+
+                    $(getDomElementIdentifier('duplicateFormName'), modal).on('keyup paste', function(e) {
+                        if ($(this).val().length > 0) {
+                            $(this).removeClass('has-error');
+                            Wizard.unlockNextStep();
+                            Wizard.set('formName', $(this).val());
+                        } else {
+                            $(this).addClass('has-error');
+                            Wizard.lockNextStep();
+                        }
+                    });
+
+                    $(getDomElementIdentifier('duplicateFormSavePath'), modal).on('change', function(e) {
+                        Wizard.set('savePath', $(getDomElementIdentifier('duplicateFormSavePath') + ' option:selected', modal).val());
+                    });
+                });
+
+                /**
+                 * Wizard step 2
+                 */
+                Wizard.addFinalProcessingSlide(function() {
+                    $.post(_formManagerApp.getAjaxEndpoint('duplicate'), {
+                        tx_form_web_formformbuilder: {
+                            formName: Wizard.setup.settings['formName'],
+                            formPersistenceIdentifier: Wizard.setup.settings['formPersistenceIdentifier'],
+                            savePath: Wizard.setup.settings['savePath']
+                        }
+                    }, function(data, textStatus, jqXHR) {
+                        document.location = data;
+                        Wizard.dismiss();
+                    }).fail(function(jqXHR, textStatus, errorThrown) {
+                        Notification.error(textStatus, errorThrown, 2);
+                        Wizard.dismiss();
+                    });
+                }).done(function() {
+                    Wizard.show();
+                });
+            });
+        };
+
+        /**
+         * @private
+         *
+         * @return void
+         */
+        function _showReferencesSetup() {
+            $(getDomElementIdentifier('showReferences')).on('click', function(e) {
+                var that, url;
+
+                e.preventDefault();
+                that = this;
+                url = _formManagerApp.getAjaxEndpoint('references') + '&tx_form_web_formformbuilder[formPersistenceIdentifier]=' + $(this).data('formPersistenceIdentifier');
+
+                $.get(url, function(data, textStatus, jqXHR) {
+                    var html, modalButtons = [], referencesLength;
+
+                    modalButtons.push({
+                        text: TYPO3.lang['formManager.cancel'],
+                        active: true,
+                        btnClass: 'btn-default',
+                        name: 'cancel',
+                        trigger: function () {
+                            Modal.currentModal.trigger('modal-dismiss');
+                        }
+                    });
+
+                    referencesLength = data['references'].length;
+                    if (referencesLength > 0) {
+                        html = '<div>'
+                                 + '<h3>' + TYPO3.lang['formManager.references.headline'].replace('{0}', $(that).data('formName')) + '</h3>'
+                             + '</div>'
+                             + '<div class="table-fit">'
+                                 + '<table id="forms" class="table table-striped table-condensed">'
+                                     + '<thead>'
+                                         + '<tr>'
+                                             + '<th>' + TYPO3.lang['formManager.page'] + '</th>'
+                                             + '<th>' + TYPO3.lang['formManager.record'] + '</th>'
+                                         + '</tr>'
+                                     + '</thead>'
+                                     + '<tbody>';
+
+                        for (var i = 0, len = data['references'].length; i < len; ++i) {
+                            html +=        '<tr>'
+                                             + '<td>' + data['references'][i]['recordPageTitle'] + '</td>'
+                                             + '<td>'
+                                                 + data['references'][i]['recordIcon']
+                                                 + '<a href="' + data['references'][i]['recordEditUrl'] + '" data-identifier="referenceLink">'
+                                                     + data['references'][i]['recordTitle'] + ' (uid: ' + data['references'][i]['recordUid'] + ')'
+                                                 + '</a>'
+                                             + '</td>'
+                                         + '</tr>';
+                        }
+
+                        html +=        '</tbody>'
+                                 + '</table>'
+                             + '</div>';
+                    } else {
+                        html = '<div>'
+                                 + '<h1>' + TYPO3.lang['formManager.references.title'].replace('{0}', data['formPersistenceIdentifier']) + '</h1>'
+                             + '</div>'
+                             + '<div>' + TYPO3.lang['formManager.no_references'] + '</div>';
+                    }
+
+                    html = $(html);
+                    $(getDomElementIdentifier('referenceLink'), html).on('click', function(e) {
+                        e.preventDefault();
+                        Modal.currentModal.trigger('modal-dismiss');
+                        document.location = $(this).prop('href');
+                    });
+
+                    Modal.show(
+                        TYPO3.lang['formManager.references.title'],
+                        html,
+                        Severity.info,
+                        modalButtons
+                    );
+                }).fail(function(jqXHR, textStatus, errorThrown) {
+                    if (jqXHR.status !== 0) {
+                        Notification.error(textStatus, errorThrown, 2);
+                    }
+                });
+            });
+        };
+
+        /**
+         * @public
+         *
+         * @param string elementIdentifier
+         * @param string type
+         * @return mixed|undefined
+         * @throws 1477506413
+         * @throws 1477506414
+         */
+        function getDomElementIdentifier(elementIdentifier, type) {
+            _formManagerApp.assert(elementIdentifier.length > 0, 'Invalid parameter "elementIdentifier"', 1477506413);
+            _formManagerApp.assert(typeof _domElementIdentifierCache[elementIdentifier] !== "undefined", 'elementIdentifier "' + elementIdentifier + '" does not exist', 1477506414);
+            if (typeof type === "undefined") {
+                type = 'identifier';
+            }
+
+            return _domElementIdentifierCache[elementIdentifier][type] || undefined;
+        };
+
+        /**
+         * @public
+         *
+         * @param object formManagerApp
+         * @return void
+         */
+        function bootstrap(formManagerApp) {
+            _formManagerApp = formManagerApp;
+            _domElementIdentifierCacheSetup();
+            _removeFormSetup();
+            _newFormSetup();
+            _duplicateFormSetup();
+            _showReferencesSetup();
+            $(getDomElementIdentifier('tooltip')).tooltip();
+        };
+
+        /**
+         * Publish the public methods.
+         * Implements the "Revealing Module Pattern".
+         */
+        return {
+            bootstrap: bootstrap,
+        };
+    })($, Modal, Severity, Wizard, Icons, Notification);
+});
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Backend/Vendor/jquery.mjs.nestedSortable.js b/typo3/sysext/form/Resources/Public/JavaScript/Backend/Vendor/jquery.mjs.nestedSortable.js
new file mode 100644
index 0000000000000000000000000000000000000000..38bf5f7eb0d75d61a528f9c9b0ee7c269a6adf82
--- /dev/null
+++ b/typo3/sysext/form/Resources/Public/JavaScript/Backend/Vendor/jquery.mjs.nestedSortable.js
@@ -0,0 +1,907 @@
+/*
+ * jQuery UI Nested Sortable
+ * v 2.1a / 2016-02-04
+ * https://github.com/ilikenwf/nestedSortable
+ *
+ * Depends on:
+ *	 jquery.ui.sortable.js 1.10+
+ *
+ * Copyright (c) 2010-2016 Manuele J Sarfatti and contributors
+ * Licensed under the MIT License
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+(function( factory ) {
+	"use strict";
+
+	if ( typeof define === "function" && define.amd ) {
+
+		// AMD. Register as an anonymous module.
+		define([
+			"jquery",
+			"jquery-ui/sortable"
+		], factory );
+	} else {
+
+		// Browser globals
+		factory( window.jQuery );
+	}
+}(function($) {
+	"use strict";
+
+	function isOverAxis( x, reference, size ) {
+		return ( x > reference ) && ( x < ( reference + size ) );
+	}
+
+	$.widget("mjs.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
+
+		options: {
+			disableParentChange: false,
+			doNotClear: false,
+			expandOnHover: 700,
+			isAllowed: function() { return true; },
+			isTree: false,
+			listType: "ol",
+			maxLevels: 0,
+			protectRoot: false,
+			rootID: null,
+			rtl: false,
+			startCollapsed: false,
+			tabSize: 20,
+
+			branchClass: "mjs-nestedSortable-branch",
+			collapsedClass: "mjs-nestedSortable-collapsed",
+			disableNestingClass: "mjs-nestedSortable-no-nesting",
+			errorClass: "mjs-nestedSortable-error",
+			expandedClass: "mjs-nestedSortable-expanded",
+			hoveringClass: "mjs-nestedSortable-hovering",
+			leafClass: "mjs-nestedSortable-leaf",
+			disabledClass: "mjs-nestedSortable-disabled"
+		},
+
+		_create: function() {
+			var self = this,
+				err;
+
+			this.element.data("ui-sortable", this.element.data("mjs-nestedSortable"));
+
+			// mjs - prevent browser from freezing if the HTML is not correct
+			if (!this.element.is(this.options.listType)) {
+				err = "nestedSortable: " +
+					"Please check that the listType option is set to your actual list type";
+
+				throw new Error(err);
+			}
+
+			// if we have a tree with expanding/collapsing functionality,
+			// force 'intersect' tolerance method
+			if (this.options.isTree && this.options.expandOnHover) {
+				this.options.tolerance = "intersect";
+			}
+
+			$.ui.sortable.prototype._create.apply(this, arguments);
+
+			// prepare the tree by applying the right classes
+			// (the CSS is responsible for actual hide/show functionality)
+			if (this.options.isTree) {
+				$(this.items).each(function() {
+					var $li = this.item,
+						hasCollapsedClass = $li.hasClass(self.options.collapsedClass),
+						hasExpandedClass = $li.hasClass(self.options.expandedClass);
+
+					if ($li.children(self.options.listType).length) {
+						$li.addClass(self.options.branchClass);
+						// expand/collapse class only if they have children
+
+						if ( !hasCollapsedClass && !hasExpandedClass ) {
+							if (self.options.startCollapsed) {
+								$li.addClass(self.options.collapsedClass);
+							} else {
+								$li.addClass(self.options.expandedClass);
+							}
+						}
+					} else {
+						$li.addClass(self.options.leafClass);
+					}
+				});
+			}
+		},
+
+		_destroy: function() {
+			this.element
+				.removeData("mjs-nestedSortable")
+				.removeData("ui-sortable");
+			return $.ui.sortable.prototype._destroy.apply(this, arguments);
+		},
+
+		_mouseDrag: function(event) {
+			var i,
+				item,
+				itemElement,
+				intersection,
+				self = this,
+				o = this.options,
+				scrolled = false,
+				$document = $(document),
+				previousTopOffset,
+				parentItem,
+				level,
+				childLevels,
+				itemAfter,
+				itemBefore,
+				newList,
+				method,
+				a,
+				previousItem,
+				nextItem,
+				helperIsNotSibling;
+
+			//Compute the helpers position
+			this.position = this._generatePosition(event);
+			this.positionAbs = this._convertPositionTo("absolute");
+
+			if (!this.lastPositionAbs) {
+				this.lastPositionAbs = this.positionAbs;
+			}
+
+			//Do scrolling
+			if (this.options.scroll) {
+				if (this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
+
+					if (
+						(
+							this.overflowOffset.top +
+							this.scrollParent[0].offsetHeight
+						) -
+						event.pageY <
+						o.scrollSensitivity
+					) {
+						scrolled = this.scrollParent.scrollTop() + o.scrollSpeed;
+						this.scrollParent.scrollTop(scrolled);
+					} else if (
+						event.pageY -
+						this.overflowOffset.top <
+						o.scrollSensitivity
+					) {
+						scrolled = this.scrollParent.scrollTop() - o.scrollSpeed;
+						this.scrollParent.scrollTop(scrolled);
+					}
+
+					if (
+						(
+							this.overflowOffset.left +
+							this.scrollParent[0].offsetWidth
+						) -
+						event.pageX <
+						o.scrollSensitivity
+					) {
+						scrolled = this.scrollParent.scrollLeft() + o.scrollSpeed;
+						this.scrollParent.scrollLeft(scrolled);
+					} else if (
+						event.pageX -
+						this.overflowOffset.left <
+						o.scrollSensitivity
+					) {
+						scrolled = this.scrollParent.scrollLeft() - o.scrollSpeed;
+						this.scrollParent.scrollLeft(scrolled);
+					}
+
+				} else {
+
+					if (
+						event.pageY -
+						$document.scrollTop() <
+						o.scrollSensitivity
+					) {
+						scrolled = $document.scrollTop() - o.scrollSpeed;
+						$document.scrollTop(scrolled);
+					} else if (
+						$(window).height() -
+						(
+							event.pageY -
+							$document.scrollTop()
+						) <
+						o.scrollSensitivity
+					) {
+						scrolled = $document.scrollTop() + o.scrollSpeed;
+						$document.scrollTop(scrolled);
+					}
+
+					if (
+						event.pageX -
+						$document.scrollLeft() <
+						o.scrollSensitivity
+					) {
+						scrolled = $document.scrollLeft() - o.scrollSpeed;
+						$document.scrollLeft(scrolled);
+					} else if (
+						$(window).width() -
+						(
+							event.pageX -
+							$document.scrollLeft()
+						) <
+						o.scrollSensitivity
+					) {
+						scrolled = $document.scrollLeft() + o.scrollSpeed;
+						$document.scrollLeft(scrolled);
+					}
+
+				}
+
+				if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+					$.ui.ddmanager.prepareOffsets(this, event);
+				}
+			}
+
+			//Regenerate the absolute position used for position checks
+			this.positionAbs = this._convertPositionTo("absolute");
+
+			// mjs - find the top offset before rearrangement,
+			previousTopOffset = this.placeholder.offset().top;
+
+			//Set the helper position
+			if (!this.options.axis || this.options.axis !== "y") {
+				this.helper[0].style.left = this.position.left + "px";
+			}
+			if (!this.options.axis || this.options.axis !== "x") {
+				this.helper[0].style.top = (this.position.top) + "px";
+			}
+
+			// mjs - check and reset hovering state at each cycle
+			this.hovering = this.hovering ? this.hovering : null;
+			this.mouseentered = this.mouseentered ? this.mouseentered : false;
+
+			// mjs - let's start caching some variables
+			(function() {
+				var _parentItem = this.placeholder.parent().parent();
+				if (_parentItem && _parentItem.closest(".ui-sortable").length) {
+					parentItem = _parentItem;
+				}
+			}.call(this));
+
+			level = this._getLevel(this.placeholder);
+			childLevels = this._getChildLevels(this.helper);
+			newList = document.createElement(o.listType);
+
+			//Rearrange
+			for (i = this.items.length - 1; i >= 0; i--) {
+
+				//Cache variables and intersection, continue if no intersection
+				item = this.items[i];
+				itemElement = item.item[0];
+				intersection = this._intersectsWithPointer(item);
+				if (!intersection) {
+					continue;
+				}
+
+				// Only put the placeholder inside the current Container, skip all
+				// items form other containers. This works because when moving
+				// an item from one container to another the
+				// currentContainer is switched before the placeholder is moved.
+				//
+				// Without this moving items in "sub-sortables" can cause the placeholder to jitter
+				// beetween the outer and inner container.
+				if (item.instance !== this.currentContainer) {
+					continue;
+				}
+
+				// No action if intersected item is disabled
+				// and the element above or below in the direction we're going is also disabled
+				if (itemElement.className.indexOf(o.disabledClass) !== -1) {
+					// Note: intersection hardcoded direction values from
+					// jquery.ui.sortable.js:_intersectsWithPointer
+					if (intersection === 2) {
+						// Going down
+						itemAfter = this.items[i + 1];
+						if (itemAfter && itemAfter.item.hasClass(o.disabledClass)) {
+							continue;
+						}
+
+					} else if (intersection === 1) {
+						// Going up
+						itemBefore = this.items[i - 1];
+						if (itemBefore && itemBefore.item.hasClass(o.disabledClass)) {
+							continue;
+						}
+					}
+				}
+
+				method = intersection === 1 ? "next" : "prev";
+
+				// cannot intersect with itself
+				// no useless actions that have been done before
+				// no action if the item moved is the parent of the item checked
+				if (itemElement !== this.currentItem[0] &&
+					this.placeholder[method]()[0] !== itemElement &&
+					!$.contains(this.placeholder[0], itemElement) &&
+					(
+						this.options.type === "semi-dynamic" ?
+							!$.contains(this.element[0], itemElement) :
+							true
+					)
+				) {
+
+					// mjs - we are intersecting an element:
+					// trigger the mouseenter event and store this state
+					if (!this.mouseentered) {
+						$(itemElement).mouseenter();
+						this.mouseentered = true;
+					}
+
+					// mjs - if the element has children and they are hidden,
+					// show them after a delay (CSS responsible)
+					if (o.isTree && $(itemElement).hasClass(o.collapsedClass) && o.expandOnHover) {
+						if (!this.hovering) {
+							$(itemElement).addClass(o.hoveringClass);
+							this.hovering = window.setTimeout(function() {
+								$(itemElement)
+									.removeClass(o.collapsedClass)
+									.addClass(o.expandedClass);
+
+								self.refreshPositions();
+								self._trigger("expand", event, self._uiHash());
+							}, o.expandOnHover);
+						}
+					}
+
+					this.direction = intersection === 1 ? "down" : "up";
+
+					// mjs - rearrange the elements and reset timeouts and hovering state
+					if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
+						$(itemElement).mouseleave();
+						this.mouseentered = false;
+						$(itemElement).removeClass(o.hoveringClass);
+						if (this.hovering) {
+							window.clearTimeout(this.hovering);
+						}
+						this.hovering = null;
+
+						// mjs - do not switch container if
+						// it's a root item and 'protectRoot' is true
+						// or if it's not a root item but we are trying to make it root
+						if (o.protectRoot &&
+							!(
+								this.currentItem[0].parentNode === this.element[0] &&
+								// it's a root item
+								itemElement.parentNode !== this.element[0]
+								// it's intersecting a non-root item
+							)
+						) {
+							if (this.currentItem[0].parentNode !== this.element[0] &&
+								itemElement.parentNode === this.element[0]
+							) {
+
+								if ( !$(itemElement).children(o.listType).length) {
+									itemElement.appendChild(newList);
+									if (o.isTree) {
+										$(itemElement)
+											.removeClass(o.leafClass)
+											.addClass(o.branchClass + " " + o.expandedClass);
+									}
+								}
+
+								if (this.direction === "down") {
+									a = $(itemElement).prev().children(o.listType);
+								} else {
+									a = $(itemElement).children(o.listType);
+								}
+
+								if (a[0] !== undefined) {
+									this._rearrange(event, null, a);
+								}
+
+							} else {
+								this._rearrange(event, item);
+							}
+						} else if (!o.protectRoot) {
+							this._rearrange(event, item);
+						}
+					} else {
+						break;
+					}
+
+					// Clear emtpy ul's/ol's
+					this._clearEmpty(itemElement);
+
+					this._trigger("change", event, this._uiHash());
+					break;
+				}
+			}
+
+			// mjs - to find the previous sibling in the list,
+			// keep backtracking until we hit a valid list item.
+			(function() {
+				var _previousItem = this.placeholder.prev();
+				if (_previousItem.length) {
+					previousItem = _previousItem;
+				} else {
+					previousItem = null;
+				}
+			}.call(this));
+
+			if (previousItem != null) {
+				while (
+					previousItem[0].nodeName.toLowerCase() !== "li" ||
+					previousItem[0].className.indexOf(o.disabledClass) !== -1 ||
+					previousItem[0] === this.currentItem[0] ||
+					previousItem[0] === this.helper[0]
+				) {
+					if (previousItem[0].previousSibling) {
+						previousItem = $(previousItem[0].previousSibling);
+					} else {
+						previousItem = null;
+						break;
+					}
+				}
+			}
+
+			// mjs - to find the next sibling in the list,
+			// keep stepping forward until we hit a valid list item.
+			(function() {
+				var _nextItem = this.placeholder.next();
+				if (_nextItem.length) {
+					nextItem = _nextItem;
+				} else {
+					nextItem = null;
+				}
+			}.call(this));
+
+			if (nextItem != null) {
+				while (
+					nextItem[0].nodeName.toLowerCase() !== "li" ||
+					nextItem[0].className.indexOf(o.disabledClass) !== -1 ||
+					nextItem[0] === this.currentItem[0] ||
+					nextItem[0] === this.helper[0]
+				) {
+					if (nextItem[0].nextSibling) {
+						nextItem = $(nextItem[0].nextSibling);
+					} else {
+						nextItem = null;
+						break;
+					}
+				}
+			}
+
+			this.beyondMaxLevels = 0;
+
+			// mjs - if the item is moved to the left, send it one level up
+			// but only if it's at the bottom of the list
+			if (parentItem != null &&
+				nextItem == null &&
+				!(o.protectRoot && parentItem[0].parentNode == this.element[0]) &&
+				(
+					o.rtl &&
+					(
+						this.positionAbs.left +
+						this.helper.outerWidth() > parentItem.offset().left +
+						parentItem.outerWidth()
+					) ||
+					!o.rtl && (this.positionAbs.left < parentItem.offset().left)
+				)
+			) {
+
+				parentItem.after(this.placeholder[0]);
+				helperIsNotSibling = !parentItem
+											.children(o.listItem)
+											.children("li:visible:not(.ui-sortable-helper)")
+											.length;
+				if (o.isTree && helperIsNotSibling) {
+					parentItem
+						.removeClass(this.options.branchClass + " " + this.options.expandedClass)
+						.addClass(this.options.leafClass);
+				}
+                if(typeof parentItem !== 'undefined')
+				    this._clearEmpty(parentItem[0]);
+				this._trigger("change", event, this._uiHash());
+				// mjs - if the item is below a sibling and is moved to the right,
+				// make it a child of that sibling
+			} else if (previousItem != null &&
+				!previousItem.hasClass(o.disableNestingClass) &&
+				(
+					previousItem.children(o.listType).length &&
+					previousItem.children(o.listType).is(":visible") ||
+					!previousItem.children(o.listType).length
+				) &&
+				!(o.protectRoot && this.currentItem[0].parentNode === this.element[0]) &&
+				(
+					o.rtl &&
+					(
+						this.positionAbs.left +
+						this.helper.outerWidth() <
+						previousItem.offset().left +
+						previousItem.outerWidth() -
+						o.tabSize
+					) ||
+					!o.rtl &&
+					(this.positionAbs.left > previousItem.offset().left + o.tabSize)
+				)
+			) {
+
+				this._isAllowed(previousItem, level, level + childLevels + 1);
+
+				if (!previousItem.children(o.listType).length) {
+					previousItem[0].appendChild(newList);
+					if (o.isTree) {
+						previousItem
+							.removeClass(o.leafClass)
+							.addClass(o.branchClass + " " + o.expandedClass);
+					}
+				}
+
+				// mjs - if this item is being moved from the top, add it to the top of the list.
+				if (previousTopOffset && (previousTopOffset <= previousItem.offset().top)) {
+					previousItem.children(o.listType).prepend(this.placeholder);
+				} else {
+					// mjs - otherwise, add it to the bottom of the list.
+					previousItem.children(o.listType)[0].appendChild(this.placeholder[0]);
+				}
+                if(typeof parentItem !== 'undefined')
+				    this._clearEmpty(parentItem[0]);
+				this._trigger("change", event, this._uiHash());
+			} else {
+				this._isAllowed(parentItem, level, level + childLevels);
+			}
+
+			//Post events to containers
+			this._contactContainers(event);
+
+			//Interconnect with droppables
+			if ($.ui.ddmanager) {
+				$.ui.ddmanager.drag(this, event);
+			}
+
+			//Call callbacks
+			this._trigger("sort", event, this._uiHash());
+
+			this.lastPositionAbs = this.positionAbs;
+			return false;
+
+		},
+
+		_mouseStop: function(event) {
+			// mjs - if the item is in a position not allowed, send it back
+			if (this.beyondMaxLevels) {
+
+				this.placeholder.removeClass(this.options.errorClass);
+
+				if (this.domPosition.prev) {
+					$(this.domPosition.prev).after(this.placeholder);
+				} else {
+					$(this.domPosition.parent).prepend(this.placeholder);
+				}
+
+				this._trigger("revert", event, this._uiHash());
+
+			}
+
+			// mjs - clear the hovering timeout, just to be sure
+			$("." + this.options.hoveringClass)
+				.mouseleave()
+				.removeClass(this.options.hoveringClass);
+
+			this.mouseentered = false;
+			if (this.hovering) {
+				window.clearTimeout(this.hovering);
+			}
+			this.hovering = null;
+
+			this._relocate_event = event;
+			this._pid_current = $(this.domPosition.parent).parent().attr("id");
+			this._sort_current = this.domPosition.prev ? $(this.domPosition.prev).next().index() : 0;
+			$.ui.sortable.prototype._mouseStop.apply(this, arguments); //asybnchronous execution, @see _clear for the relocate event.
+		},
+
+		// mjs - this function is slightly modified
+		// to make it easier to hover over a collapsed element and have it expand
+		_intersectsWithSides: function(item) {
+
+			var half = this.options.isTree ? .8 : .5,
+				isOverBottomHalf = isOverAxis(
+					this.positionAbs.top + this.offset.click.top,
+					item.top + (item.height * half),
+					item.height
+				),
+				isOverTopHalf = isOverAxis(
+					this.positionAbs.top + this.offset.click.top,
+					item.top - (item.height * half),
+					item.height
+				),
+				isOverRightHalf = isOverAxis(
+					this.positionAbs.left + this.offset.click.left,
+					item.left + (item.width / 2),
+					item.width
+				),
+				verticalDirection = this._getDragVerticalDirection(),
+				horizontalDirection = this._getDragHorizontalDirection();
+
+			if (this.floating && horizontalDirection) {
+				return (
+					(horizontalDirection === "right" && isOverRightHalf) ||
+					(horizontalDirection === "left" && !isOverRightHalf)
+				);
+			} else {
+				return verticalDirection && (
+					(verticalDirection === "down" && isOverBottomHalf) ||
+					(verticalDirection === "up" && isOverTopHalf)
+				);
+			}
+
+		},
+
+		_contactContainers: function() {
+
+			if (this.options.protectRoot && this.currentItem[0].parentNode === this.element[0] ) {
+				return;
+			}
+
+			$.ui.sortable.prototype._contactContainers.apply(this, arguments);
+
+		},
+
+		_clear: function() {
+			var i,
+				item;
+
+			$.ui.sortable.prototype._clear.apply(this, arguments);
+
+			//relocate event
+			if (!(this._pid_current === this._uiHash().item.parent().parent().attr("id") &&
+				this._sort_current === this._uiHash().item.index())) {
+				this._trigger("relocate", this._relocate_event, this._uiHash());
+			}
+
+			// mjs - clean last empty ul/ol
+			for (i = this.items.length - 1; i >= 0; i--) {
+				item = this.items[i].item[0];
+				this._clearEmpty(item);
+			}
+
+		},
+
+		serialize: function(options) {
+
+			var o = $.extend({}, this.options, options),
+				items = this._getItemsAsjQuery(o && o.connected),
+				str = [];
+
+			$(items).each(function() {
+				var res = ($(o.item || this).attr(o.attribute || "id") || "")
+						.match(o.expression || (/(.+)[-=_](.+)/)),
+					pid = ($(o.item || this).parent(o.listType)
+						.parent(o.items)
+						.attr(o.attribute || "id") || "")
+						.match(o.expression || (/(.+)[-=_](.+)/));
+
+				if (res) {
+					str.push(
+						(
+							(o.key || res[1]) +
+							"[" +
+							(o.key && o.expression ? res[1] : res[2]) + "]"
+						) +
+						"=" +
+						(pid ? (o.key && o.expression ? pid[1] : pid[2]) : o.rootID));
+				}
+			});
+
+			if (!str.length && o.key) {
+				str.push(o.key + "=");
+			}
+
+			return str.join("&");
+
+		},
+
+		toHierarchy: function(options) {
+
+			var o = $.extend({}, this.options, options),
+				ret = [];
+
+			$(this.element).children(o.items).each(function() {
+				var level = _recursiveItems(this);
+				ret.push(level);
+			});
+
+			return ret;
+
+			function _recursiveItems(item) {
+				var id = ($(item).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[-=_](.+)/)),
+					currentItem;
+
+				var data = $(item).data();
+				if (data.nestedSortableItem) {
+					delete data.nestedSortableItem; // Remove the nestedSortableItem object from the data
+				}
+
+				if (id) {
+					currentItem = {
+						"id": id[2]
+					};
+
+					currentItem = $.extend({}, currentItem, data); // Combine the two objects
+
+					if ($(item).children(o.listType).children(o.items).length > 0) {
+						currentItem.children = [];
+						$(item).children(o.listType).children(o.items).each(function() {
+							var level = _recursiveItems(this);
+							currentItem.children.push(level);
+						});
+					}
+					return currentItem;
+				}
+			}
+		},
+
+		toArray: function(options) {
+
+			var o = $.extend({}, this.options, options),
+				sDepth = o.startDepthCount || 0,
+				ret = [],
+				left = 1;
+
+			if (!o.excludeRoot) {
+				ret.push({
+					"item_id": o.rootID,
+					"parent_id": null,
+					"depth": sDepth,
+					"left": left,
+					"right": ($(o.items, this.element).length + 1) * 2
+				});
+				left++;
+			}
+
+			$(this.element).children(o.items).each(function() {
+				left = _recursiveArray(this, sDepth, left);
+			});
+
+			ret = ret.sort(function(a, b) { return (a.left - b.left); });
+
+			return ret;
+
+			function _recursiveArray(item, depth, _left) {
+
+				var right = _left + 1,
+					id,
+					pid,
+					parentItem;
+
+				if ($(item).children(o.listType).children(o.items).length > 0) {
+					depth++;
+					$(item).children(o.listType).children(o.items).each(function() {
+						right = _recursiveArray($(this), depth, right);
+					});
+					depth--;
+				}
+
+				id = ($(item).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[-=_](.+)/));
+
+				if (depth === sDepth) {
+					pid = o.rootID;
+				} else {
+					parentItem = ($(item).parent(o.listType)
+											.parent(o.items)
+											.attr(o.attribute || "id"))
+											.match(o.expression || (/(.+)[-=_](.+)/));
+					pid = parentItem[2];
+				}
+
+				if (id) {
+					var data = $(item).children('div').data();
+					var itemObj = $.extend( data, {
+						"id":id[2],
+						"parent_id":pid,
+						"depth":depth,
+						"left":_left,
+						"right":right
+						} );
+					ret.push( itemObj );
+				}
+
+				_left = right + 1;
+				return _left;
+			}
+
+		},
+
+		_clearEmpty: function (item) {
+			function replaceClass(elem, search, replace, swap) {
+				if (swap) {
+					search = [replace, replace = search][0];
+				}
+
+				$(elem).removeClass(search).addClass(replace);
+			}
+
+			var o = this.options,
+				childrenList = $(item).children(o.listType),
+				hasChildren = childrenList.has('li').length;
+
+			var doNotClear =
+				o.doNotClear ||
+				hasChildren ||
+				o.protectRoot && $(item)[0] === this.element[0];
+
+			if (o.isTree) {
+				replaceClass(item, o.branchClass, o.leafClass, doNotClear);
+			}
+
+			if (!doNotClear) {
+				childrenList.parent().removeClass(o.expandedClass);
+				childrenList.remove();
+			}
+		},
+
+		_getLevel: function(item) {
+
+			var level = 1,
+				list;
+
+			if (this.options.listType) {
+				list = item.closest(this.options.listType);
+				while (list && list.length > 0 && !list.is(".ui-sortable")) {
+					level++;
+					list = list.parent().closest(this.options.listType);
+				}
+			}
+
+			return level;
+		},
+
+		_getChildLevels: function(parent, depth) {
+			var self = this,
+				o = this.options,
+				result = 0;
+			depth = depth || 0;
+
+			$(parent).children(o.listType).children(o.items).each(function(index, child) {
+				result = Math.max(self._getChildLevels(child, depth + 1), result);
+			});
+
+			return depth ? result + 1 : result;
+		},
+
+		_isAllowed: function(parentItem, level, levels) {
+			var o = this.options,
+				// this takes into account the maxLevels set to the recipient list
+				maxLevels = this
+					.placeholder
+					.closest(".ui-sortable")
+					.nestedSortable("option", "maxLevels"),
+
+				// Check if the parent has changed to prevent it, when o.disableParentChange is true
+				oldParent = this.currentItem.parent().parent(),
+				disabledByParentchange = o.disableParentChange && (
+					//From somewhere to somewhere else, except the root
+					typeof parentItem !== 'undefined' && !oldParent.is(parentItem) ||
+					typeof parentItem === 'undefined' && oldParent.is("li")	//From somewhere to the root
+				);
+			// mjs - is the root protected?
+			// mjs - are we nesting too deep?
+			if (
+				disabledByParentchange ||
+				!o.isAllowed(this.placeholder, parentItem, this.currentItem)
+			) {
+				this.placeholder.addClass(o.errorClass);
+				if (maxLevels < levels && maxLevels !== 0) {
+					this.beyondMaxLevels = levels - maxLevels;
+				} else {
+					this.beyondMaxLevels = 1;
+				}
+			} else {
+				if (maxLevels < levels && maxLevels !== 0) {
+					this.placeholder.addClass(o.errorClass);
+					this.beyondMaxLevels = levels - maxLevels;
+				} else {
+					this.placeholder.removeClass(o.errorClass);
+					this.beyondMaxLevels = 0;
+				}
+			}
+		}
+
+	}));
+
+	$.mjs.nestedSortable.prototype.options = $.extend(
+		{},
+		$.ui.sortable.prototype.options,
+		$.mjs.nestedSortable.prototype.options
+	);
+}));
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard.js
deleted file mode 100644
index 3be1fa180bd786263880d058275922b40289badb..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard.js
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-function configureWizardApplication() {
-	var basicdeps = [
-		//'TYPO3',
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Elements/ButtonGroup',
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Button',
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Checkbox',
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Fieldset',
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Fileupload',
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Hidden',
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Password',
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Radio',
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Reset',
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Select',
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Submit',
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Textarea',
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Textline'
-	];
-	requirejs.config({shim: {
-		//'extjs': {exports: 'Ext'},
-		//'TYPO3': {exports: 'TYPO3'},
-		'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.isemptyobject': {exports: 'Ext.isemptyobject', deps: []},
-		'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.merge': {exports: 'Ext.merge', deps: []},
-		'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.spinner': {exports: 'Ext.ux.Spinner', deps: []},
-		'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.form.textfieldsubmit': {exports: 'Ext.ux.form.textfieldsubmit', deps: []},
-		'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.form.spinnerfield': {exports: 'Ext.ux.form.SpinnerField', deps: ['TYPO3/CMS/Form/Wizard/Ux/Ext.ux.spinner']},
-		'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.form.FakeFormPanel': {exports: 'Ext.ux.form.FakeFormPanel', deps: []},
-		'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.form.ValueCheckbox': {exports: 'Ext.ux.form.ValueCheckbox', deps: []},
-		'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.grid.CheckColumn': {exports: 'Ext.ux.grid.CheckColumn', deps: []},
-		'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.grid.SingleSelectCheckColumn': {exports: 'Ext.ux.grid.SingleSelectCheckColumn', deps: ['TYPO3/CMS/Form/Wizard/Ux/Ext.ux.grid.CheckColumn']},
-		'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.grid.ItemDeleter': {exports: 'Ext.ux.grid.ItemDeleter', deps: []},
-		'TYPO3/CMS/Form/Wizard/Settings': {exports: 'TYPO3.Form.Wizard.Settings', deps: []}, // defined during require callback
-		'TYPO3/CMS/Form/Wizard/Helpers/History': {exports: 'TYPO3.Form.Wizard.Helpers.History', deps: []},
-		'TYPO3/CMS/Form/Wizard/Helpers/Element': {exports: 'TYPO3.Form.Wizard.Helpers.Element', deps: []},
-		'TYPO3/CMS/Form/Wizard/Elements/Dummy': {exports: 'TYPO3.Form.Wizard.Elements.Dummy', deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Elements/ButtonGroup': {exports: 'TYPO3.Form.Wizard.ButtonGroup', deps: []},
-		'TYPO3/CMS/Form/Wizard/Elements/Container': {exports: 'TYPO3.Form.Wizard.Container', deps: ['TYPO3/CMS/Form/Wizard/Elements/Dummy', 'TYPO3/CMS/Form/Wizard/Elements/Content/Header', 'TYPO3/CMS/Form/Wizard/Elements/Predefined/RadioGroup', 'TYPO3/CMS/Form/Wizard/Elements/Predefined/Email', 'TYPO3/CMS/Form/Wizard/Elements/Predefined/CheckboxGroup', 'TYPO3/CMS/Form/Wizard/Elements/Predefined/Name']},
-		'TYPO3/CMS/Form/Wizard/Elements/Elements': {exports: 'TYPO3.Form.Wizard.Elements', deps: ['TYPO3/CMS/Form/Wizard/Helpers/Element', 'TYPO3/CMS/Form/Wizard/Helpers/History', 'TYPO3/CMS/Form/Wizard/Elements/ButtonGroup']},
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Form': {exports: 'TYPO3.Form.Wizard.Elements.Basic.Form', deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements', 'TYPO3/CMS/Form/Wizard/Elements/Container']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Right': {exports: 'TYPO3.Form.Wizard.Viewport.Right', deps: ['TYPO3/CMS/Form/Wizard/Viewport', 'TYPO3/CMS/Form/Wizard/Elements/Basic/Form']},
-		'TYPO3/CMS/Form/Wizard/Elements/Content/Header':        {exports: 'TYPO3.Form.Wizard.Elements.Content.Header',        deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Elements/Content/Textblock':     {exports: 'TYPO3.Form.Wizard.Elements.Content.Textblock',     deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Elements/Content': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Elements.Content', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Elements/ButtonGroup', 'TYPO3/CMS/Form/Wizard/Elements/Content/Header', 'TYPO3/CMS/Form/Wizard/Elements/Content/Textblock']},
-		'TYPO3/CMS/Form/Wizard/Elements/Predefined/Email':         {exports: 'TYPO3.Form.Wizard.Elements.Predefined.Email',         deps: ['TYPO3/CMS/Form/Wizard/Elements/Basic/Textline']},
-		'TYPO3/CMS/Form/Wizard/Elements/Predefined/CheckboxGroup': {exports: 'TYPO3.Form.Wizard.Elements.Predefined.CheckboxGroup', deps: ['TYPO3/CMS/Form/Wizard/Elements/Basic/Fieldset', 'TYPO3/CMS/Form/Wizard/Elements/Basic/Checkbox']},
-		'TYPO3/CMS/Form/Wizard/Elements/Predefined/Name':          {exports: 'TYPO3.Form.Wizard.Elements.Predefined.Name',          deps: ['TYPO3/CMS/Form/Wizard/Elements/Basic/Fieldset', 'TYPO3/CMS/Form/Wizard/Elements/Basic/Textline']},
-		'TYPO3/CMS/Form/Wizard/Elements/Predefined/RadioGroup':    {exports: 'TYPO3.Form.Wizard.Elements.Predefined.RadioGroup',    deps: ['TYPO3/CMS/Form/Wizard/Elements/Basic/Fieldset', 'TYPO3/CMS/Form/Wizard/Elements/Basic/Radio', 'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.merge']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Elements/Predefined': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Elements.Predefined', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Elements/ButtonGroup']},
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Textline':   {exports: 'TYPO3.Form.Wizard.Elements.Basic.Textline',   deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Textarea':   {exports: 'TYPO3.Form.Wizard.Elements.Basic.Textarea',   deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Submit':     {exports: 'TYPO3.Form.Wizard.Elements.Basic.Submit',     deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Select':     {exports: 'TYPO3.Form.Wizard.Elements.Basic.Select',     deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Reset':      {exports: 'TYPO3.Form.Wizard.Elements.Basic.Reset',      deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Radio':      {exports: 'TYPO3.Form.Wizard.Elements.Basic.Radio',      deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Password':   {exports: 'TYPO3.Form.Wizard.Elements.Basic.Password',   deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Hidden':     {exports: 'TYPO3.Form.Wizard.Elements.Basic.Hidden',     deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Fileupload': {exports: 'TYPO3.Form.Wizard.Elements.Basic.Fileupload', deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Fieldset':   {exports: 'TYPO3.Form.Wizard.Elements.Basic.Fieldset',   deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Checkbox':   {exports: 'TYPO3.Form.Wizard.Elements.Basic.Checkbox',   deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Elements/Basic/Button':     {exports: 'TYPO3.Form.Wizard.Elements.Basic.Button',     deps: ['TYPO3/CMS/Form/Wizard/Elements/Elements']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Elements/Basic': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Elements.Basic', deps: basicdeps},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Elements/ButtonGroup': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Elements.ButtonGroup', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Elements']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Elements': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Elements', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Options':    {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Options',    deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.grid.SingleSelectCheckColumn', 'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.grid.ItemDeleter']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Label':      {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Label', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.form.FakeFormPanel']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Dummy': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Dummy', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Filter': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Alphabetic':    {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Alphabetic',    deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Filter']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Alphanumeric':  {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Alphanumeric',  deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Filter']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Currency':      {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Currency',      deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Filter']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Digit':         {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Digit',         deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Filter']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Integer':       {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Integer',       deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Filter']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/LowerCase':     {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.LowerCase',     deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Filter']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/RegExp':        {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.RegExp',        deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Filter']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/StripNewLines': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.StripNewLines', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Filter']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/TitleCase':     {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.TitleCase',     deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Filter']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Trim':          {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Trim',          deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Filter']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/UpperCase':     {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.UpperCase',     deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Filter']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Dummy']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Legend':     {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Legend', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.form.FakeFormPanel']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule':     {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule',     deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation', 'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.form.FakeFormPanel']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Required': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Required', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Dummy':    {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Dummy',    deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Alphabetic':       {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Alphabetic', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Alphanumeric':     {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Alphanumeric', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Between':          {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Between', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Date':             {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Date', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Digit':            {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Digit', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Email':            {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Email', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Equals':           {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Equals', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/FileAllowedTypes': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileAllowedTypes', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/FileMaximumSize':  {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileMaximumSize', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/FileMinimumSize':  {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileMinimumSize', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Float':            {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Float', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/GreaterThan':      {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.GreaterThan', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/InArray':          {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.InArray', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Integer':          {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Integer', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Ip':               {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Ip', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Length':           {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Length', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/LessThan':         {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.LessThan', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/RegExp':           {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.RegExp', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Uri':              {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Uri', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Rule']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Dummy']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Various':    {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Various', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.form.FakeFormPanel']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Attributes': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Attributes', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options', 'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.form.ValueCheckbox', 'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.form.FakeFormPanel', 'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.form.spinnerfield']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Panel': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Panel', deps: [
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Legend',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Label',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Alphabetic',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Alphanumeric',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Currency',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Digit',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Integer',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/LowerCase',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/RegExp',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/StripNewLines',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/TitleCase',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/Trim',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters/UpperCase',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Filters',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Various',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Alphabetic',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Alphanumeric',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Between',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Date',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Digit',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Email',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Equals',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/FileAllowedTypes',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/FileMaximumSize',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/FileMinimumSize',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Float',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/GreaterThan',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/InArray',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Integer',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Ip',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Length',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/LessThan',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/RegExp',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Required',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation/Uri',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Validation',
-			'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Options'
-		]},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Dummy': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options.Dummy', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Options': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Options', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/PostProcessors/Dummy': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.Dummy', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Form']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/PostProcessors/PostProcessor': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.PostProcessor', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Form']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/PostProcessors/Mail': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.Mail', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Form', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/PostProcessors/PostProcessor']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/PostProcessors/Redirect': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.Redirect', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Form', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/PostProcessors/PostProcessor']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/PostProcessor': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessor', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Form', 'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.isemptyobject', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/PostProcessors/Dummy', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/PostProcessors/Mail', 'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/PostProcessors/Redirect']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/Attributes': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Form.Attributes', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Attributes']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/Prefix': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Form.Prefix', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Form', 'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.form.textfieldsubmit', 'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.form.FakeFormPanel']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/Behaviour': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Form.Behaviour', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left/Form', 'TYPO3/CMS/Form/Wizard/Ux/Ext.ux.form.FakeFormPanel']},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left/Form': {exports: 'TYPO3.Form.Wizard.Viewport.Left.Form', deps: ['TYPO3/CMS/Form/Wizard/Viewport/Left'/*, 'TYPO3/CMS/Form/Wizard/Settings'*/]},
-		'TYPO3/CMS/Form/Wizard/Viewport/Left': {exports: 'TYPO3.Form.Wizard.Viewport.Left', deps: ['TYPO3/CMS/Form/Wizard/Viewport'/*, 'TYPO3/CMS/Form/Wizard/Settings'*/]},
-		'TYPO3/CMS/Form/Wizard/Viewport': {exports: 'TYPO3.Form.Wizard.Viewport', deps: []}
-	}});
-}
-configureWizardApplication();
-
-/**
- * Initialization script of TYPO3 form Wizard
- */
-define('TYPO3/CMS/Form/Wizard', [
-	//'extjs',
-	//'TYPO3',
-	'TYPO3/CMS/Backend/SplitButtons',
-	'TYPO3/CMS/Form/Wizard/Settings',
-	'TYPO3/CMS/Form/Wizard/Viewport/Left/Elements/Content',
-	'TYPO3/CMS/Form/Wizard/Viewport/Left/Elements/Predefined',
-	'TYPO3/CMS/Form/Wizard/Viewport/Left/Elements/Basic',
-	'TYPO3/CMS/Form/Wizard/Viewport/Left/Elements',
-	'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Forms/Options',
-	'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Panel',
-	'TYPO3/CMS/Form/Wizard/Viewport/Left/Options/Dummy',
-	'TYPO3/CMS/Form/Wizard/Viewport/Left/Options',
-	'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/PostProcessor',
-	'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/Attributes',
-	'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/Prefix',
-	'TYPO3/CMS/Form/Wizard/Viewport/Left/Form/Behaviour',
-	'TYPO3/CMS/Form/Wizard/Viewport/Left/Form',
-	'TYPO3/CMS/Form/Wizard/Viewport/Left',
-	'TYPO3/CMS/Form/Wizard/Elements/Basic/Form',
-	'TYPO3/CMS/Form/Wizard/Viewport/Right',
-	'TYPO3/CMS/Form/Wizard/Viewport'
-], function (//Ext,
-			 //TYPO3,
-			 SplitButtons,
-			 TYPO3_CMS_Form_Wizard_Settings,
-			 TYPO3_CMS_Form_Wizard_Viewport_Left_Elements_Content,
-			 TYPO3_CMS_Form_Wizard_Viewport_Left_Elements_Predefined,
-			 TYPO3_CMS_Form_Wizard_Viewport_Left_Elements_Basic,
-			 TYPO3_CMS_Form_Wizard_Viewport_Left_Elements,
-			 TYPO3_CMS_Form_Wizard_Viewport_Left_Options_Forms_Options,
-			 TYPO3_CMS_Form_Wizard_Viewport_Left_Options_Panel,
-			 TYPO3_CMS_Form_Wizard_Viewport_Left_Options_Dummy,
-			 TYPO3_CMS_Form_Wizard_Viewport_Left_Options,
-			 TYPO3_CMS_Form_Wizard_Viewport_Left_Form_PostProcessor,
-			 TYPO3_CMS_Form_Wizard_Viewport_Left_Form_Attributes,
-			 TYPO3_CMS_Form_Wizard_Viewport_Left_Form_Prefix,
-			 TYPO3_CMS_Form_Wizard_Viewport_Left_Form_Behaviour,
-			 TYPO3_CMS_Form_Wizard_Viewport_Left_Form,
-			 TYPO3_CMS_Form_Wizard_Viewport_Left,
-			 TYPO3_CMS_Form_Wizard_Elements_Basic_Form,
-			 TYPO3_CMS_Form_Wizard_Viewport_Right,
-			 TYPO3_CMS_Form_Wizard_Viewport
-) {
-	/**
-	 * called when built as Object with "new"
-	 * 
-	 * @constructor
-	 */
-	var Wizard = function() {
-		this.initialize();
-	};
-
-	Wizard.prototype.initialize = function() {
-		Ext.onReady(function() {
-			var transportElId = Ext.get('form-wizard-element-container').dom.getAttribute('rel');
-			var transportEl = Ext.get(transportElId).dom;
-			var viewport = new TYPO3.Form.Wizard.Viewport({
-				renderTo: 'form-wizard-element',
-				transportEl: transportEl,
-				splitButtons: SplitButtons
-			});
-			// When the window is resized, the viewport has to be resized as well
-			Ext.EventManager.onWindowResize(viewport.doLayout, viewport);
-			var relayoutFunction = function(ev) {
-				// bootstrap tab handling
-				var controlsId = ev.target.getAttribute('aria-controls');
-				if(controlsId) {
-					var wizardEl = ev.target.parentNode.parentNode.parentNode.querySelector('#' + controlsId + ' ' + '#form-wizard-element');
-					if(wizardEl) {
-						// we are earlier then bootstrap tab
-						setTimeout(function(){
-							viewport.doLayout();
-						}, 200);
-					}
-				}
-			};
-			
-			// register tab change events
-			/** @var tabsLinks {NodeList} */
-			var tabsLinks = document.querySelectorAll('a[data-toggle="tab"]');
-			/** @see https://code.google.com/p/v8/issues/detail?id=3953 */
-			for(var i = 0; i < tabsLinks.length; i++) {
-				var e = tabsLinks[i];
-				// event not called, maybe jQuery only
-				//e.addEventListener('shown.bs.tab', relayoutFunction, false);
-				e.addEventListener('click', relayoutFunction, false);
-			}
-		});
-	};
-
-	/**
-	 * executed when module required, return value will be 'this'
-	 * @return Wizard
-	 */
-	return function() {
-		return new Wizard();
-	}();
-});
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Button.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Button.js
deleted file mode 100644
index bfb59a933013734c5420942582db5edba08aa882..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Button.js
+++ /dev/null
@@ -1,107 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Basic');
-
-/**
- * The BUTTON element
- *
- * @class TYPO3.Form.Wizard.Elements.Basic.Button
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Basic.Button = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'button',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'front\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-			'<input {[this.getAttributes(values.attributes)]} />',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'back\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-		'</div>',
-		{
-			compiled: true,
-			getMessage: function(rules) {
-				var messageHtml = '';
-				var messages = [];
-				Ext.iterate(rules, function(rule, configuration) {
-					if (configuration.showMessage) {
-						messages.push(configuration.message);
-					}
-				}, this);
-
-				messageHtml = ' <em>' + messages.join(', ') + '</em>';
-				return messageHtml;
-
-			},
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					'accesskey': '',
-					'class': '',
-					'contenteditable': '',
-					'contextmenu': '',
-					'dir': '',
-					'draggable': '',
-					'dropzone': '',
-					'hidden': '',
-					'id': '',
-					'lang': '',
-					'spellcheck': '',
-					'style': '',
-					'tabindex': '',
-					'title': '',
-					'translate': '',
-
-					'autofocus': '',
-					'disabled': '',
-					'name': '',
-					'type': 'button',
-					'value': TYPO3.l10n.localize('tx_form_domain_model_element_button.value')
-				},
-				filters: {},
-				label: {
-					value: TYPO3.l10n.localize('elements_label')
-				},
-				layout: 'front',
-				validation: {}
-			}
-		});
-		TYPO3.Form.Wizard.Elements.Basic.Button.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-basic-button', TYPO3.Form.Wizard.Elements.Basic.Button);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Checkbox.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Checkbox.js
deleted file mode 100644
index 5091d747a03876bcae21b59c907787132addde3e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Checkbox.js
+++ /dev/null
@@ -1,110 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Basic');
-
-/**
- * The CHECKBOX element
- *
- * @class TYPO3.Form.Wizard.Elements.Basic.Checkbox
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Basic.Checkbox = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'x-checkbox',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'front\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-			'<input {[this.getAttributes(values.attributes)]} />',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'back\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-		'</div>',
-		{
-			compiled: true,
-			getMessage: function(rules) {
-				var messageHtml = '';
-				var messages = [];
-				Ext.iterate(rules, function(rule, configuration) {
-					if (configuration.showMessage) {
-						messages.push(configuration.message);
-					}
-				}, this);
-
-				messageHtml = ' <em>' + messages.join(', ') + '</em>';
-				return messageHtml;
-
-			},
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					'accesskey': '',
-					'class': '',
-					'contenteditable': '',
-					'contextmenu': '',
-					'dir': '',
-					'draggable': '',
-					'dropzone': '',
-					'hidden': '',
-					'id': '',
-					'lang': '',
-					'spellcheck': '',
-					'style': '',
-					'tabindex': '',
-					'title': '',
-					'translate': '',
-
-					'autofocus': '',
-					'checked': '',
-					'disabled': '',
-					'name': '',
-					'readonly': '',
-					'required': '',
-					'type': 'checkbox',
-					'value': ''
-				},
-				filters: {},
-				label: {
-					value: TYPO3.l10n.localize('elements_label')
-				},
-				layout: 'back',
-				validation: {}
-			}
-		});
-		TYPO3.Form.Wizard.Elements.Basic.Checkbox.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-basic-checkbox', TYPO3.Form.Wizard.Elements.Basic.Checkbox);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Fieldset.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Fieldset.js
deleted file mode 100644
index d8558e68f1fe95fcf9a07f13ebea2c6b1a2d2179..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Fieldset.js
+++ /dev/null
@@ -1,130 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Basic');
-
-/**
- * The FIELDSET element
- *
- * @class TYPO3.Form.Wizard.Elements.Basic.Fieldset
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Basic.Fieldset = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'fieldset',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div>',
-			'<fieldset {[this.getAttributes(values.attributes)]}>',
-			'<tpl for="legend">',
-				'<tpl if="value">',
-					'<legend>{value}</legend>',
-				'</tpl>',
-			'</tpl>',
-			'<ol></ol>',
-			'</fieldset>',
-		'</div>',
-		{
-			compiled: true,
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * @cfg {Array} elementContainer
-	 * Configuration for the containerComponent
-	 */
-	elementContainer: {
-		hasDragAndDrop: true
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					"class": '',
-					dir: '',
-					id: '',
-					lang: '',
-					style: ''
-				},
-				legend: {
-					value: TYPO3.l10n.localize('elements_legend')
-				}
-			}
-		});
-
-		TYPO3.Form.Wizard.Elements.Basic.Fieldset.superclass.constructor.apply(this, arguments);
-	},
-
-	/**
-	 * Constructor
-	 */
-	initComponent: function() {
-		var config = {};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// Initialize the container component
-		this.containerComponent = new TYPO3.Form.Wizard.Container(this.elementContainer);
-
-			// call parent
-		TYPO3.Form.Wizard.Elements.Basic.Fieldset.superclass.initComponent.apply(this, arguments);
-
-			// Initialize events after rendering
-		this.on('afterrender', this.afterRender, this);
-	},
-
-	/**
-	 * Called by the 'afterrender' event.
-	 *
-	 * Add the container component to this component
-	 */
-	afterRender: function() {
-		this.addContainerAfterRender();
-
-			// Call parent
-		TYPO3.Form.Wizard.Elements.Basic.Form.superclass.afterRender.call(this);
-	},
-
-	/**
-	 * Add the container component to this component
-	 *
-	 * Because we are using a XTemplate for rendering this component, we can
-	 * only add the container after rendering, because the <ol> tag needs to be
-	 * replaced with this container.
-	 *
-	 * The container needs to be rerendered when a configuration parameter
-	 * (legend or attributes) of the ownerCt, for instance fieldset, has changed
-	 * otherwise it will not show up
-	 */
-	addContainerAfterRender: function() {
-		this.containerComponent.applyToMarkup(this.getEl().child('ol'));
-		this.containerComponent.rendered = false;
-		this.containerComponent.render();
-		this.containerComponent.doLayout();
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-basic-fieldset', TYPO3.Form.Wizard.Elements.Basic.Fieldset);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Fileupload.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Fileupload.js
deleted file mode 100644
index 9c65d00e1167e5e0d59045e601c30820b5ac968d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Fileupload.js
+++ /dev/null
@@ -1,111 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Basic');
-
-/**
- * The FILEUPLOAD element
- *
- * @class TYPO3.Form.Wizard.Elements.Basic.Fileupload
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Basic.Fileupload = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'fileupload',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'front\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-			'<input {[this.getAttributes(values.attributes)]} />',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'back\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-		'</div>',
-		{
-			compiled: true,
-			getMessage: function(rules) {
-				var messageHtml = '';
-				var messages = [];
-				Ext.iterate(rules, function(rule, configuration) {
-					if (configuration.showMessage) {
-						messages.push(configuration.message);
-					}
-				}, this);
-
-				messageHtml = ' <em>' + messages.join(', ') + '</em>';
-				return messageHtml;
-
-			},
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					'accesskey': '',
-					'class': '',
-					'contenteditable': '',
-					'contextmenu': '',
-					'dir': '',
-					'draggable': '',
-					'dropzone': '',
-					'hidden': '',
-					'id': '',
-					'lang': '',
-					'spellcheck': '',
-					'style': '',
-					'tabindex': '',
-					'title': '',
-					'translate': '',
-
-					'accept': '',
-					'autofocus': '',
-					'disabled': '',
-					'multiple': '',
-					'name': '',
-					'readonly': '',
-					'required': '',
-					'type': 'file',
-					'value': ''
-				},
-				filters: {},
-				label: {
-					value: TYPO3.l10n.localize('elements_label')
-				},
-				layout: 'front',
-				validation: {}
-			}
-		});
-		TYPO3.Form.Wizard.Elements.Basic.Fileupload.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-basic-fileupload', TYPO3.Form.Wizard.Elements.Basic.Fileupload);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Form.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Form.js
deleted file mode 100644
index d14d96e50e7713b1efc702a88bc21e9e6124c77b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Form.js
+++ /dev/null
@@ -1,176 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Basic');
-
-/**
- * The FORM element
- *
- * @class TYPO3.Form.Wizard.Elements.Basic.Form
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Basic.Form = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {Mixed} autoEl
-	 * A tag name or DomHelper spec used to create the Element which will
-	 * encapsulate this Component.
-	 */
-	autoEl: 'li',
-
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'form',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 *
-	 * Adding novalidate attribute avoids HTML5 validation of elements.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div id="fake-form" {[this.getAttributes(values.attributes)]} novalidate="novalidate">',
-			'<ol></ol>',
-		'</div>',
-		{
-			compiled: true,
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * @cfg {Boolean} isEditable
-	 * Defines whether the element is editable. If the item is editable,
-	 * a button group with remove and edit buttons will be added to this element
-	 * and when the the element is clicked, an event is triggered to edit the
-	 * element. Some elements, like the dummy, don't need this.
-	 */
-	isEditable: false,
-
-	/**
-	 * @cfg {Array} elementContainer
-	 * Configuration for the containerComponent
-	 */
-	elementContainer: {
-		hasDragAndDrop: true
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					'accesskey': '',
-					'class': '',
-					'contenteditable': '',
-					'contextmenu': '',
-					'dir': '',
-					'draggable': '',
-					'dropzone': '',
-					'hidden': '',
-					'id': '',
-					'lang': '',
-					'spellcheck': '',
-					'style': '',
-					'tabindex': '',
-					'title': '',
-					'translate': '',
-
-					'accept': '',
-					'accept-charset': '',
-					'action': '',
-					'autocomplete': '',
-					'enctype': 'application/x-www-form-urlencoded',
-					'method': 'post',
-					'novalidate': ''
-				},
-				prefix: 'tx_form',
-				confirmation: true,
-				postProcessor: {
-					mail: {
-						recipientEmail: '',
-						senderEmail: ''
-					},
-					redirect: {
-						destination: ''
-					}
-				}
-			}
-		});
-		TYPO3.Form.Wizard.Elements.Basic.Form.superclass.constructor.apply(this, arguments);
-	},
-
-	/**
-	 * Constructor
-	 */
-	initComponent: function() {
-		var config = {};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// Initialize the container component
-		this.containerComponent = new TYPO3.Form.Wizard.Container(this.elementContainer);
-
-			// Call parent
-		TYPO3.Form.Wizard.Elements.Basic.Form.superclass.initComponent.apply(this, arguments);
-
-			// Initialize events after rendering
-		this.on('afterrender', this.afterRender, this);
-	},
-
-	/**
-	 * Called by the 'afterrender' event.
-	 *
-	 * Add the container component to this component
-	 * Stop the submit event of the form, because this form does not need to be
-	 * submitted
-	 */
-	afterRender: function() {
-		this.addContainerAfterRender();
-
-			// Call parent
-		TYPO3.Form.Wizard.Elements.Basic.Form.superclass.afterRender.call(this);
-	},
-
-	/**
-	 * Add the container component to this component
-	 *
-	 * Because we are using a XTemplate for rendering this component, we can
-	 * only add the container after rendering, because the <ol> tag needs to be
-	 * replaced with this container.
-	 */
-	addContainerAfterRender: function() {
-		this.containerComponent.applyToMarkup(this.getEl().child('ol'));
-		this.containerComponent.rendered = false;
-		this.containerComponent.render();
-		this.containerComponent.doLayout();
-	},
-
-	/**
-	 * Remove a post processor from this element
-	 *
-	 * @param type
-	 */
-	removePostProcessor: function(type) {
-		if (this.configuration.postProcessor[type]) {
-			delete this.configuration.postProcessor[type];
-			TYPO3.Form.Wizard.Helpers.History.setHistory();
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-basic-form', TYPO3.Form.Wizard.Elements.Basic.Form);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Hidden.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Hidden.js
deleted file mode 100644
index abd6067af5507407380f2fa527ce668088717fdf..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Hidden.js
+++ /dev/null
@@ -1,88 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Basic');
-
-/**
- * The HIDDEN element
- *
- * @class TYPO3.Form.Wizard.Elements.Basic.Hidden
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Basic.Hidden = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'hidden-element',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<p class="hidden-dummy-element">{[this.getAttributes(values.attributes, \'name\')]}</p>',
-			'<input {[this.getAttributes(values.attributes)]} />',
-		'</div>',
-		{
-			compiled: true,
-			getAttributes: function(attributes, filterBy) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (typeof filterBy != 'undefined') {
-						if (key == filterBy) {
-							attributesHtml = value;
-							return;
-						} else {
-							return;
-						}
-					}
-
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					'accesskey': '',
-					'class': '',
-					'contenteditable': '',
-					'contextmenu': '',
-					'dir': '',
-					'draggable': '',
-					'dropzone': '',
-					'hidden': '',
-					'id': '',
-					'lang': '',
-					'spellcheck': '',
-					'style': '',
-					'tabindex': '',
-					'title': '',
-					'translate': '',
-
-					'name': '',
-					'type': 'hidden',
-					'value': ''
-				},
-				filters: {},
-				validation: {}
-			}
-		});
-		TYPO3.Form.Wizard.Elements.Basic.Hidden.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-basic-hidden', TYPO3.Form.Wizard.Elements.Basic.Hidden);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Password.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Password.js
deleted file mode 100644
index 60d2ac8c66bd286169541635ecc48f61bebb8786..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Password.js
+++ /dev/null
@@ -1,115 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Basic');
-
-/**
- * The PASSWORD element
- *
- * @class TYPO3.Form.Wizard.Elements.Basic.Password
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Basic.Password = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'password',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'front\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-			'<input {[this.getAttributes(values.attributes)]} />',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'back\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-		'</div>',
-		{
-			compiled: true,
-			getMessage: function(rules) {
-				var messageHtml = '';
-				var messages = [];
-				Ext.iterate(rules, function(rule, configuration) {
-					if (configuration.showMessage) {
-						messages.push(configuration.message);
-					}
-				}, this);
-
-				messageHtml = ' <em>' + messages.join(', ') + '</em>';
-				return messageHtml;
-
-			},
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					'accesskey': '',
-					'class': '',
-					'contenteditable': '',
-					'contextmenu': '',
-					'dir': '',
-					'draggable': '',
-					'dropzone': '',
-					'hidden': '',
-					'id': '',
-					'lang': '',
-					'spellcheck': '',
-					'style': '',
-					'tabindex': '',
-					'title': '',
-					'translate': '',
-
-					'autocomplete': '',
-					'autofocus': '',
-					'disabled': '',
-					'maxlength': '',
-					'minlength': '',
-					'name': '',
-					'pattern': '',
-					'placeholder': '',
-					'readonly': '',
-					'required': '',
-					'size': '',
-					'type': 'password',
-					'value': ''
-				},
-				filters: {},
-				label: {
-					value: TYPO3.l10n.localize('elements_label')
-				},
-				layout: 'front',
-				validation: {}
-			}
-		});
-		TYPO3.Form.Wizard.Elements.Basic.Password.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-basic-password', TYPO3.Form.Wizard.Elements.Basic.Password);
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Radio.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Radio.js
deleted file mode 100644
index b5cf1d6711fc9a6ba17e33328b80dcc50e4091d0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Radio.js
+++ /dev/null
@@ -1,110 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Basic');
-
-/**
- * The RADIO element
- *
- * @class TYPO3.Form.Wizard.Elements.Basic.Radio
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Basic.Radio = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'x-radio',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'front\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-			'<input {[this.getAttributes(values.attributes)]} />',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'back\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-		'</div>',
-		{
-			compiled: true,
-			getMessage: function(rules) {
-				var messageHtml = '';
-				var messages = [];
-				Ext.iterate(rules, function(rule, configuration) {
-					if (configuration.showMessage) {
-						messages.push(configuration.message);
-					}
-				}, this);
-
-				messageHtml = ' <em>' + messages.join(', ') + '</em>';
-				return messageHtml;
-
-			},
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					'accesskey': '',
-					'class': '',
-					'contenteditable': '',
-					'contextmenu': '',
-					'dir': '',
-					'draggable': '',
-					'dropzone': '',
-					'hidden': '',
-					'id': '',
-					'lang': '',
-					'spellcheck': '',
-					'style': '',
-					'tabindex': '',
-					'title': '',
-					'translate': '',
-
-					'autofocus': '',
-					'checked': '',
-					'disabled': '',
-					'name': '',
-					'readonly': '',
-					'required': '',
-					'type': 'radio',
-					'value': ''
-				},
-				filters: {},
-				label: {
-					value: TYPO3.l10n.localize('elements_label')
-				},
-				layout: 'back',
-				validation: {}
-			}
-		});
-		TYPO3.Form.Wizard.Elements.Basic.Radio.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-basic-radio', TYPO3.Form.Wizard.Elements.Basic.Radio);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Reset.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Reset.js
deleted file mode 100644
index 9893aa7d5dcb00a7b02cce78f6096fc60f162f8f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Reset.js
+++ /dev/null
@@ -1,137 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Basic');
-
-/**
- * The RESET element
- *
- * @class TYPO3.Form.Wizard.Elements.Basic.Reset
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Basic.Reset = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'reset',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'front\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-			'<input {[this.getAttributes(values.attributes)]} />',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'back\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-		'</div>',
-		{
-			compiled: true,
-			getMessage: function(rules) {
-				var messageHtml = '';
-				var messages = [];
-				Ext.iterate(rules, function(rule, configuration) {
-					if (configuration.showMessage) {
-						messages.push(configuration.message);
-					}
-				}, this);
-
-				messageHtml = ' <em>' + messages.join(', ') + '</em>';
-				return messageHtml;
-
-			},
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Constructor
-	 */
-	initComponent: function() {
-
-		// call parent
-		TYPO3.Form.Wizard.Elements.Basic.Reset.superclass.initComponent.apply(this, arguments);
-
-		// Initialize events after rendering
-		this.on('afterrender', this.afterRender, this);
-	},
-
-	/**
-	 * Called by the 'afterrender' event.
-	 *
-	 * Stop click propagation
-	 */
-	afterRender: function() {
-		this.getEl().addListener('click', function(e) {
-			if(e.type == 'click') {
-				e.stopEvent();
-			}
-		});
-
-		// Call parent
-		TYPO3.Form.Wizard.Elements.Basic.Reset.superclass.afterRender.call(this);
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					'accesskey': '',
-					'class': '',
-					'contenteditable': '',
-					'contextmenu': '',
-					'dir': '',
-					'draggable': '',
-					'dropzone': '',
-					'hidden': '',
-					'id': '',
-					'lang': '',
-					'spellcheck': '',
-					'style': '',
-					'tabindex': '',
-					'title': '',
-					'translate': '',
-
-					'autofocus': '',
-					'checked': '',
-					'disabled': '',
-					'name': '',
-					'required': '',
-					'type': 'reset',
-					'value': TYPO3.l10n.localize('tx_form_domain_model_element_reset.value')
-				},
-				filters: {},
-				label: {
-					value: ''
-				},
-				layout: 'front',
-				validation: {}
-			}
-		});
-		TYPO3.Form.Wizard.Elements.Basic.Reset.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-basic-reset', TYPO3.Form.Wizard.Elements.Basic.Reset);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Select.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Select.js
deleted file mode 100644
index f8e1560606821b44f357121ed6792e6cd06c5434..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Select.js
+++ /dev/null
@@ -1,130 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Basic');
-
-/**
- * The SELECT element
- *
- * @class TYPO3.Form.Wizard.Elements.Basic.Select
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Basic.Select = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'select',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'front\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-			'<select {[this.getAttributes(values.attributes)]}>',
-				'<tpl for="options">',
-					'<option {[this.getAttributes(values.attributes)]}>{text}</option>',
-				'</tpl>',
-			'</select>',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'back\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-		'</div>',
-		{
-			compiled: true,
-			getMessage: function(rules) {
-				var messageHtml = '';
-				var messages = [];
-				Ext.iterate(rules, function(rule, configuration) {
-					if (configuration.showMessage) {
-						messages.push(configuration.message);
-					}
-				}, this);
-
-				messageHtml = ' <em>' + messages.join(', ') + '</em>';
-				return messageHtml;
-
-			},
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					'accesskey': '',
-					'class': '',
-					'contenteditable': '',
-					'contextmenu': '',
-					'dir': '',
-					'draggable': '',
-					'dropzone': '',
-					'hidden': '',
-					'id': '',
-					'lang': '',
-					'spellcheck': '',
-					'style': '',
-					'tabindex': '',
-					'title': '',
-					'translate': '',
-
-					'autofocus': '',
-					'disabled': '',
-					'multiple': '',
-					'name': '',
-					'required': '',
-					'size': ''
-				},
-				filters: {},
-				label: {
-					value: TYPO3.l10n.localize('elements_label')
-				},
-				options: [
-					{
-						text: TYPO3.l10n.localize('elements_option_1'),
-						attributes: {
-							value: TYPO3.l10n.localize('elements_value_1')
-						}
-					}, {
-						text: TYPO3.l10n.localize('elements_option_2'),
-						attributes: {
-							value: TYPO3.l10n.localize('elements_value_2')
-						}
-					}, {
-						text: TYPO3.l10n.localize('elements_option_3'),
-						attributes: {
-							value: TYPO3.l10n.localize('elements_value_3')
-						}
-					}
-				],
-				layout: 'front',
-				validation: {}
-			}
-		});
-		TYPO3.Form.Wizard.Elements.Basic.Select.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-basic-select', TYPO3.Form.Wizard.Elements.Basic.Select);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Submit.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Submit.js
deleted file mode 100644
index 7e683baba6685ece03a061325b61be0e9d6f320a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Submit.js
+++ /dev/null
@@ -1,135 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Basic');
-
-/**
- * The SUBMIT element
- *
- * @class TYPO3.Form.Wizard.Elements.Basic.Submit
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Basic.Submit = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'submit',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'front\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-			'<input {[this.getAttributes(values.attributes)]} />',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'back\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-		'</div>',
-		{
-			compiled: true,
-			getMessage: function(rules) {
-				var messageHtml = '';
-				var messages = [];
-				Ext.iterate(rules, function(rule, configuration) {
-					if (configuration.showMessage) {
-						messages.push(configuration.message);
-					}
-				}, this);
-
-				messageHtml = ' <em>' + messages.join(', ') + '</em>';
-				return messageHtml;
-
-			},
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Constructor
-	 */
-	initComponent: function() {
-
-		// call parent
-		TYPO3.Form.Wizard.Elements.Basic.Submit.superclass.initComponent.apply(this, arguments);
-
-		// Initialize events after rendering
-		this.on('afterrender', this.afterRender, this);
-	},
-
-	/**
-	 * Called by the 'afterrender' event.
-	 *
-	 * Stop click propagation
-	 */
-	afterRender: function() {
-		this.getEl().addListener('click', function(e) {
-			if(e.type == 'click') {
-				e.stopEvent();
-			}
-		});
-
-		// Call parent
-		TYPO3.Form.Wizard.Elements.Basic.Submit.superclass.afterRender.call(this);
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					'accesskey': '',
-					'class': '',
-					'contenteditable': '',
-					'contextmenu': '',
-					'dir': '',
-					'draggable': '',
-					'dropzone': '',
-					'hidden': '',
-					'id': '',
-					'lang': '',
-					'spellcheck': '',
-					'style': '',
-					'tabindex': '',
-					'title': '',
-					'translate': '',
-
-					'autofocus': '',
-					'disabled': '',
-					'name': '',
-					'type': 'submit',
-					'value': TYPO3.l10n.localize('tx_form_domain_model_element_submit.value')
-				},
-				filters: {},
-				label: {
-					value: ''
-				},
-				layout: 'front',
-				validation: {}
-			}
-		});
-		TYPO3.Form.Wizard.Elements.Basic.Submit.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-basic-submit', TYPO3.Form.Wizard.Elements.Basic.Submit);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Textarea.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Textarea.js
deleted file mode 100644
index 267391c6ae9499ad688a96e7314942f05ab005d4..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Textarea.js
+++ /dev/null
@@ -1,118 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Basic');
-
-/**
- * The TEXTAREA element
- *
- * @class TYPO3.Form.Wizard.Elements.Basic.Textarea
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Basic.Textarea = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'textarea',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'front\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-			'<textarea {[this.getAttributes(values.attributes)]}>{values.attributes.text}</textarea>',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'back\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-		'</div>',
-		{
-			compiled: true,
-			getMessage: function(rules) {
-				var messageHtml = '';
-				var messages = [];
-				Ext.iterate(rules, function(rule, configuration) {
-					if (configuration.showMessage) {
-						messages.push(configuration.message);
-					}
-				}, this);
-
-				messageHtml = ' <em>' + messages.join(', ') + '</em>';
-				return messageHtml;
-
-			},
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					'accesskey': '',
-					'class': '',
-					'contenteditable': '',
-					'contextmenu': '',
-					'dir': '',
-					'draggable': '',
-					'dropzone': '',
-					'hidden': '',
-					'id': '',
-					'lang': '',
-					'spellcheck': '',
-					'style': '',
-					'tabindex': '',
-					'title': '',
-					'translate': '',
-
-					'autofocus': '',
-					'cols': '40',
-					'disabled': '',
-					'inputmode': '',
-					'maxlength': '',
-					'minlength': '',
-					'name': '',
-					'placeholder': '',
-					'readonly': '',
-					'required': '',
-					'rows': '5',
-					'selectionDirection': '',
-					'selectionEnd': '',
-					'selectionStart': '',
-					'text': '',
-					'wrap': ''
-				},
-				filters: {},
-				label: {
-					value: TYPO3.l10n.localize('elements_label')
-				},
-				layout: 'front',
-				validation: {}
-			}
-		});
-		TYPO3.Form.Wizard.Elements.Basic.Textarea.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-basic-textarea', TYPO3.Form.Wizard.Elements.Basic.Textarea);
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Textline.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Textline.js
deleted file mode 100644
index 523f040be5cc61e1aea45fc15664411d86bdcd8e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Basic/Textline.js
+++ /dev/null
@@ -1,117 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Basic');
-
-/**
- * The TEXTLINE element
- *
- * @class TYPO3.Form.Wizard.Elements.Basic.Textline
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Basic.Textline = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'textline',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'front\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-			'<input {[this.getAttributes(values.attributes)]} />',
-			'<tpl for="label">',
-				'<tpl if="value && parent.layout == \'back\'">',
-					'<label for="">{value}{[this.getMessage(parent.validation)]}</label>',
-				'</tpl>',
-			'</tpl>',
-		'</div>',
-		{
-			compiled: true,
-			getMessage: function(rules) {
-				var messageHtml = '';
-				var messages = [];
-				Ext.iterate(rules, function(rule, configuration) {
-					if (configuration.showMessage) {
-						messages.push(configuration.message);
-					}
-				}, this);
-
-				messageHtml = ' <em>' + messages.join(', ') + '</em>';
-				return messageHtml;
-
-			},
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					'accesskey': '',
-					'class': '',
-					'contenteditable': '',
-					'contextmenu': '',
-					'dir': '',
-					'draggable': '',
-					'dropzone': '',
-					'hidden': '',
-					'id': '',
-					'lang': '',
-					'spellcheck': '',
-					'style': '',
-					'tabindex': '',
-					'title': '',
-					'translate': '',
-
-					'autocomplete': '',
-					'autofocus': '',
-					'disabled': '',
-					'inputmode': '',
-					'list': '',
-					'maxlength': '',
-					'minlength': '',
-					'name': '',
-					'pattern': '',
-					'placeholder': '',
-					'readonly': '',
-					'required': '',
-					'size': '',
-					'type': 'text',
-					'value': ''
-				},
-				filters: {},
-				label: {
-					value: TYPO3.l10n.localize('elements_label')
-				},
-				layout: 'front',
-				validation: {}
-			}
-		});
-		TYPO3.Form.Wizard.Elements.Basic.Textline.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-basic-textline', TYPO3.Form.Wizard.Elements.Basic.Textline);
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/ButtonGroup.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/ButtonGroup.js
deleted file mode 100644
index 434f558a74e2ca259d8f43ad56aa61bfc20832e0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/ButtonGroup.js
+++ /dev/null
@@ -1,89 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard');
-
-/**
- * Button group to show on top of the form elements
- *
- * Most elements contain buttons to delete or edit the item. These buttons are
- * grouped in this component
- *
- * @class TYPO3.Form.Wizard.ButtonGroup
- * @extends Ext.Container
- */
-TYPO3.Form.Wizard.ButtonGroup = Ext.extend(Ext.Container, {
-	/**
-	 * @cfg {String} cls
-	 * An optional extra CSS class that will be added to this component's
-	 * Element (defaults to ''). This can be useful for adding customized styles
-	 * to the component or any of its children using standard CSS rules.
-	 */
-	cls: 'buttongroup',
-
-	/**
-	 * @cfg {Object|Function} defaults
-	 * This option is a means of applying default settings to all added items
-	 * whether added through the items config or via the add or insert methods.
-	 */
-	defaults: {
-		xtype: 'button',
-		template: new Ext.Template(
-			'<span id="{4}"><button type="{0}" class="{3}"></button></span>'
-		),
-		tooltipType: 'title'
-	},
-
-	/** @cfg {Boolean} forceLayout
-	 * If true the container will force a layout initially even if hidden or
-	 * collapsed. This option is useful for forcing forms to render in collapsed
-	 * or hidden containers. (defaults to false).
-	 */
-	forceLayout: true,
-
-	/**
-	 * Constructor
-	 */
-	initComponent: function() {
-		var config = {
-			items: [
-				{
-					iconCls: 't3-icon t3-icon-actions t3-icon-actions-edit t3-icon-edit-delete',
-					tooltip: TYPO3.l10n.localize('elements_button_delete'),
-					handler: this.removeElement,
-					scope: this
-				}, {
-					iconCls: 't3-icon t3-icon-actions t3-icon-actions-document t3-icon-document-open',
-					tooltip: TYPO3.l10n.localize('elements_button_edit'),
-					handler: this.setActive,
-					scope: this
-				}
-			]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.ButtonGroup.superclass.initComponent.apply(this, arguments);
-	},
-
-	/**
-	 * Called by the click event of the remove button
-	 *
-	 * When clicking the remove button a confirmation will be asked by the
-	 * container this button group is in.
-	 */
-	removeElement: function(button, event) {
-		event.stopPropagation();
-		this.ownerCt.confirmDeleteElement();
-	},
-
-	/**
-	 * Called by the click event of the edit button
-	 *
-	 * Tells the element helper that this component is set as the active one
-	 */
-	setActive: function(button, event) {
-		this.ownerCt.setActive(event, event.getTarget());
-	}
-});
-
-Ext.reg('typo3-form-wizard-buttongroup', TYPO3.Form.Wizard.ButtonGroup);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Container.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Container.js
deleted file mode 100644
index 1c2080e7931b6b0000f1c37f0ede076a1a57a5ba..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Container.js
+++ /dev/null
@@ -1,569 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard');
-
-/**
- * Container abstract
- *
- * There are only two containers in a form, the form itself and fieldsets.
- *
- * @class TYPO3.Form.Wizard.Elements.Container
- * @extends Ext.Container
- */
-TYPO3.Form.Wizard.Container = Ext.extend(Ext.Container, {
-	/**
-	 * @cfg {Mixed} autoEl
-	 * A tag name or DomHelper spec used to create the Element which will
-	 * encapsulate this Component.
-	 */
-	autoEl: 'ol',
-
-	/**
-	 * @cfg {String} cls
-	 * An optional extra CSS class that will be added to this component's
-	 * Element (defaults to ''). This can be useful for adding customized styles
-	 * to the component or any of its children using standard CSS rules.
-	 */
-	cls: 'formwizard-container',
-
-	/**
-	 * @cfg {Object|Function} defaults
-	 * This option is a means of applying default settings to all added items
-	 * whether added through the items config or via the add or insert methods.
-	 */
-	defaults: {
-		autoHeight: true
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the dummy to the container
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			items: [
-				{
-					xtype: 'typo3-form-wizard-elements-dummy'
-				}
-			]
-		});
-		TYPO3.Form.Wizard.Container.superclass.constructor.apply(this, arguments);
-	},
-
-
-	/**
-	 * Constructor
-	 */
-	initComponent: function() {
-		var config = {};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Container.superclass.initComponent.apply(this, arguments);
-
-			// Initialize the drag and drop zone after rendering
-		if (this.hasDragAndDrop) {
-			this.on('render', this.initializeDragAndDrop, this);
-		}
-
-		this.on('render', this.checkOnEmpty, this);
-
-			// Initialize the remove event, which will be fired when a component is removed from this container
-		this.on('remove', this.checkOnEmpty, this);
-	},
-
-	/**
-	 * Initialize the drag and drop zones
-	 *
-	 * @param container
-	 */
-	initializeDragAndDrop: function(container) {
-		/**
-		 * Initialize the drag zone
-		 *
-		 * A container can contain elements which can be moved within this and
-		 * other (nested) containers.
-		 */
-		container.dragZone = new Ext.dd.DragZone(container.getEl(), {
-			/**
-			 * Called when a mousedown occurs in this container. Looks in Ext.dd.Registry
-			 * for a valid target to drag based on the mouse down. Override this method
-			 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
-			 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
-			 * @param {EventObject} element The mouse down event element
-			 * @return {Object} The dragData
-			 */
-			getDragData: function(element) {
-				var sourceElement = element.getTarget('.formwizard-element');
-				var sourceComponent = Ext.getCmp(sourceElement.id);
-				if (sourceElement && sourceComponent.isEditable) {
-					clonedElement = sourceElement.cloneNode(true);
-					clonedElement.id = Ext.id();
-					return container.dragData = {
-						sourceEl: sourceElement,
-						repairXY: Ext.fly(sourceElement).getXY(),
-						ddel: clonedElement
-					};
-				}
-			},
-
-			onStartDrag: function(x, y) {
-				Ext.getCmp('formwizard').addClass('hover-move');
-			},
-
-			endDrag: function(event) {
-				Ext.getCmp('formwizard').removeClass('hover-move');
-			},
-
-			/**
-			 * Called before a repair of an invalid drop to get the XY to animate to.
-			 * By default returns the XY of this.dragData.ddel
-			 * @param {EventObject} e The mouse up event
-			 * @return {Array} The xy location (e.g. [100, 200])
-			 */
-			getRepairXY: function(e) {
-				return container.dragData.repairXY;
-			}
-		});
-
-		/**
-		 * Initialize the drop zone
-		 *
-		 * A container can receive other form elements or other (nested) containers.
-		 */
-		container.dropZone = new Ext.dd.DropZone(container.getEl(), {
-			/**
-			 * Returns a custom data object associated with the DOM node that is the target of the event.  By default
-			 * this looks up the event target in the Ext.dd.Registry, although you can override this method to
-			 * provide your own custom lookup.
-			 *
-			 * The override has been done here to define if we are having this event on the container or a form element.
-			 *
-			 * @param {Event} e The event
-			 * @return {Object} data The custom data
-			 */
-			getTargetFromEvent: function(event) {
-
-				var containerElement = container.getEl();
-				var formElementTarget = event.getTarget('.formwizard-element', 10, true);
-				var formContainerTarget = event.getTarget('.formwizard-container', 10, true);
-				var placeholderTarget = event.getTarget('#element-placeholder', 10, false);
-
-				if (placeholderTarget) {
-					formElementTarget = Ext.DomQuery.selectNode('.target-hover');
-				}
-
-				if (
-					container.hasDragAndDrop &&
-					formContainerTarget &&
-					formElementTarget &&
-					formContainerTarget.findParentNode('li', 10, true) == formElementTarget &&
-					formContainerTarget == containerElement
-				) {
-					return null;
-					// We are having this event on a form element
-				} else if (
-					container.hasDragAndDrop &&
-					formElementTarget
-				) {
-					if (placeholderTarget) {
-						return formElementTarget;
-					}
-					return event.getTarget('.formwizard-element');
-					// We are having this event on a container
-				} else {
-					return null;
-				}
-			},
-
-			/**
-			 * Called while the DropZone determines that a Ext.dd.DragSource is being dragged over it,
-			 * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
-			 * it should be overridden to provide the proper feedback if necessary.
-			 *
-			 * And so we did ;-) We are not using containers which can receive different elements, so we always return
-			 * Ext.dd.DropZone.prototype.dropAllowed CSS class.
-			 *
-			 * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
-			 * @param {Event} e The event
-			 * @param {Object} data An object containing arbitrary data supplied by the drag source
-			 * @return {String} status The CSS class that communicates the drop status back to the source so that the
-			 * underlying Ext.dd.StatusProxy can be updated
-			 */
-			onContainerOver: function(dd, e, data) {
-				if (Ext.get('element-placeholder')) {
-					Ext.get('element-placeholder').remove();
-				}
-				return Ext.dd.DropZone.prototype.dropAllowed;
-			},
-
-			/**
-			 * Called when the DropZone determines that a Ext.dd.DragSource has been dropped on it,
-			 * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
-			 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
-			 * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
-			 *
-			 * This is a tricky part. Because we are using multiple dropzones which are on top of each other, the event will
-			 * be called multiple times, for each group one time. We cannot prevent this by disabling event bubbling and we
-			 * dont't want to override the core of ExtJS. To prevent multiple creation of the same object, we add the variable
-			 * 'processed' to the 'data' object. If it has been processed on drop, it will not be done a second time.
-			 *
-			 * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
-			 * @param {Event} e The event
-			 * @param {Object} data An object containing arbitrary data supplied by the drag source
-			 * @return {Boolean} True if the drop was valid, else false
-			 */
-			onContainerDrop: function(dd, e, data) {
-				if (
-					container.hasDragAndDrop &&
-					!data.processed
-				) {
-					var dropComponent = Ext.getCmp(data.sourceEl.id);
-					container.dropElement(dropComponent, 'container');
-					data.processed = true;
-				}
-				return true;
-			},
-
-			/**
-			 * Called when the DropZone determines that a Ext.dd.DragSource has entered a drop node
-			 * that has either been registered or detected by a configured implementation of getTargetFromEvent.
-			 * This method has no default implementation and should be overridden to provide
-			 * node-specific processing if necessary.
-			 *
-			 * Our implementation adds a dummy placeholder before or after the element the user is hovering over.
-			 * This placeholder will show the user where the dragged element will be dropped in the form.
-			 *
-			 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
-			 * getTargetFromEvent for this node)
-			 * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
-			 * @param {Event} e The event
-			 * @param {Object} data An object containing arbitrary data supplied by the drag source
-			 */
-			onNodeEnter : function(target, dd, e, data) {
-				if (
-					Ext.get(data.sourceEl).hasClass('formwizard-element') &&
-					target.id != data.sourceEl.id
-				) {
-					var dropPosition = this.getDropPosition(target, dd);
-					if (dropPosition == 'above') {
-						Ext.DomHelper.insertBefore(target, {
-							tag: 'li',
-							id: 'element-placeholder',
-							html: '&nbsp;'
-						});
-					} else {
-						Ext.DomHelper.insertAfter(target, {
-							tag: 'li',
-							id: 'element-placeholder',
-							html: '&nbsp;'
-						});
-					}
-					Ext.fly(target).addClass('target-hover');
-				}
-			},
-
-			/**
-			 * Called when the DropZone determines that a Ext.dd.DragSource has been dragged out of
-			 * the drop node without dropping.  This method has no default implementation and should be overridden to provide
-			 * node-specific processing if necessary.
-			 *
-			 * Removes the temporary placeholder and the hover class from the element
-			 *
-			 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
-			 * getTargetFromEvent for this node)
-			 * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
-			 * @param {Event} e The event
-			 * @param {Object} data An object containing arbitrary data supplied by the drag source
-			 */
-			onNodeOut : function(target, dd, e, data) {
-				if (
-						Ext.get(data.sourceEl).hasClass('formwizard-element') &&
-						target.id != data.sourceEl.id
-					) {
-					if (e.type != 'mouseup') {
-						if (Ext.get('element-placeholder')) {
-							Ext.get('element-placeholder').remove();
-						}
-						Ext.fly(target).removeClass('target-hover');
-					}
-				}
-			},
-
-			/**
-			 * Called while the DropZone determines that a Ext.dd.DragSource is over a drop node
-			 * that has either been registered or detected by a configured implementation of getTargetFromEvent.
-			 * The default implementation returns this.dropNotAllowed, so it should be
-			 * overridden to provide the proper feedback.
-			 *
-			 * Based on the cursor position on the node we are hovering over, the temporary placeholder will be put
-			 * above or below this node. If the position changes, the placeholder will be removed and put at the
-			 * right spot.
-			 *
-			 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
-			 * getTargetFromEvent for this node)
-			 * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
-			 * @param {Event} e The event
-			 * @param {Object} data An object containing arbitrary data supplied by the drag source
-			 * @return {String} status The CSS class that communicates the drop status back to the source so that the
-			 * underlying Ext.dd.StatusProxy can be updated
-			 */
-			onNodeOver: function(target, dd, e, data) {
-				if (
-						Ext.get(data.sourceEl).hasClass('formwizard-element') &&
-						target.id != data.sourceEl.id
-				) {
-					var dropPosition = this.getDropPosition(target, dd);
-						// The position of the target moved to the top
-					if (
-						dropPosition == 'above' &&
-						target.nextElementSibling &&
-						target.nextElementSibling.id == 'element-placeholder'
-					) {
-						Ext.get('element-placeholder').remove();
-						Ext.DomHelper.insertBefore(target, {
-							tag: 'li',
-							id: 'element-placeholder',
-							html: '&nbsp;'
-						});
-					} else if (
-						dropPosition == 'below' &&
-						target.previousElementSibling &&
-						target.previousElementSibling.id == 'element-placeholder'
-					) {
-						Ext.get('element-placeholder').remove();
-						Ext.DomHelper.insertAfter(target, {
-							tag: 'li',
-							id: 'element-placeholder',
-							html: '&nbsp;'
-						});
-					}
-					return Ext.dd.DropZone.prototype.dropAllowed;
-				} else {
-					return Ext.dd.DropZone.prototype.dropNotAllowed;
-				}
-			},
-
-			/**
-			 * Called when the DropZone determines that a Ext.dd.DragSource has been dropped onto
-			 * the drop node.  The default implementation returns false, so it should be overridden to provide the
-			 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
-			 *
-			 * Like onContainerDrop this is a tricky part. Because we are using multiple dropzones which are on top of each other, the event will
-			 * be called multiple times, for each group one time. We cannot prevent this by disabling event bubbling and we
-			 * dont't want to override the core of ExtJS. To prevent multiple creation of the same object, we add the variable
-			 * 'processed' to the 'data' object. If it has been processed on drop, it will not be done a second time.
-			 *
-			 *
-			 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
-			 * getTargetFromEvent for this node)
-			 * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
-			 * @param {Event} e The event
-			 * @param {Object} data An object containing arbitrary data supplied by the drag source
-			 * @return {Boolean} True if the drop was valid, else false
-			 */
-			onNodeDrop : function(target, dd, e, data) {
-				if (
-					Ext.get(data.sourceEl).hasClass('formwizard-element') &&
-					target.id != data.sourceEl.id &&
-					!data.processed
-				) {
-
-					var dropPosition = this.getDropPosition(target, dd);
-					var dropComponent = Ext.getCmp(data.sourceEl.id);
-					container.dropElement(dropComponent, dropPosition, target);
-					data.processed = true;
-					return true;
-				}
-			},
-			/**
-			 * Defines whether we are hovering at the top or bottom half of a node
-			 *
-			 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
-			 * getTargetFromEvent for this node)
-			 * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
-			 * @return {String} above when hovering over the top half, below if at the bottom half.
-			 */
-			getDropPosition: function(target, dd) {
-				var top = Ext.lib.Dom.getY(target);
-				var bottom = top + target.offsetHeight;
-				var center = ((bottom - top) / 2) + top;
-				var yPosition = dd.lastPageY + dd.deltaY;
-				if (yPosition < center) {
-					return 'above';
-				} else if (yPosition >= center) {
-					return 'below';
-				}
-			}
-		});
-	},
-
-	/**
-	 * Called by the dropzones onContainerDrop or onNodeDrop.
-	 * Adds the component to the container.
-	 *
-	 * This function will look if it is a new element from the left buttons, if
-	 * it is an existing element which is moved within this or from another
-	 * container. It also decides if it is dropped within an empty container or
-	 * if it needs a position within the existing elements of this container.
-	 *
-	 * @param component
-	 * @param position
-	 * @param target
-	 */
-	dropElement: function(component, position, target) {
-			// Check if there are errors in the current active element
-		var optionsTabIsValid = Ext.getCmp('formwizard-left-options').tabIsValid();
-
-		var id = component.id;
-		var droppedElement = {};
-
-		if (Ext.get('element-placeholder')) {
-			Ext.get('element-placeholder').remove();
-		}
-			// Only add or move an element when there is no error in the current active element
-		if (optionsTabIsValid) {
-				// New element in container
-			if (position == 'container') {
-					// Check if the dummy is present, which means there are no elements
-				var dummy = this.findById('dummy');
-				if (dummy) {
-					this.remove(dummy, true);
-				}
-					// Add the new element to the container
-				if (component.xtype != 'button') {
-					droppedElement = this.add(
-						component
-					);
-				} else {
-					droppedElement = this.add({
-						xtype: 'typo3-form-wizard-elements-' + id
-					});
-				}
-
-				// Moved an element within this container
-			} else if (this.findById(id)) {
-				droppedElement = this.findById(id);
-				var movedElementIndex = 0;
-				var targetIndex = this.items.findIndex('id', target.id);
-
-				if (position == 'above') {
-					movedElementIndex = targetIndex;
-				} else {
-					movedElementIndex = targetIndex + 1;
-				}
-
-					// Tricky part, because this.remove does not remove the DOM element
-					// See http://www.sencha.com/forum/showthread.php?102190
-					// 1. remove component from container w/o destroying (2nd argument false)
-					// 2. remove component's element from container and append it to body
-					// 3. add/insert the component to the correct place back in the container
-					// 4. call doLayout() on the container
-				this.remove(droppedElement, false);
-				var element = Ext.get(droppedElement.id);
-				element.appendTo(Ext.getBody());
-
-				this.insert(
-					movedElementIndex,
-					droppedElement
-				);
-
-				// New element for this container coming from another one
-			} else {
-				var index = 0;
-				var targetIndex = this.items.findIndex('id', target.id);
-
-				if (position == 'above') {
-					index = targetIndex;
-				} else {
-					index = targetIndex + 1;
-				}
-
-					// Element moved
-				if (component.xtype != 'button') {
-					droppedElement = this.insert(
-						index,
-						component
-					);
-					// Coming from buttons
-				} else {
-					droppedElement = this.insert(
-						index,
-						{
-							xtype: 'typo3-form-wizard-elements-' + id
-						}
-					);
-				}
-			}
-			this.doLayout();
-			TYPO3.Form.Wizard.Helpers.History.setHistory();
-			TYPO3.Form.Wizard.Helpers.Element.setActive(droppedElement);
-
-			// The current active element has errors, show it!
-		} else {
-			Ext.MessageBox.show({
-				title: TYPO3.l10n.localize('options_error'),
-				msg: TYPO3.l10n.localize('options_error_message'),
-				icon: Ext.MessageBox.ERROR,
-				buttons: Ext.MessageBox.OK
-			});
-		}
-	},
-
-	/**
-	 * Remove the element from this container
-	 *
-	 * @param element
-	 */
-	removeElement: function(element) {
-		this.remove(element);
-		TYPO3.Form.Wizard.Helpers.History.setHistory();
-	},
-
-	/**
-	 * Called by the 'remove' event of this container.
-	 *
-	 * If an item has been removed from this container, except for the dummy
-	 * element, it will look if there are other items existing. If not, it will
-	 * put the dummy in this container to tell the user the container needs items.
-	 *
-	 * @param container
-	 * @param component
-	 */
-	checkOnEmpty: function(container, component) {
-		if (component && component.id != 'dummy' || !component) {
-			if (this.items.getCount() == 0) {
-				this.add({
-					xtype: 'typo3-form-wizard-elements-dummy'
-				});
-				this.doLayout();
-			}
-		}
-	},
-
-	/**
-	 * Called by the parent of this component when a change has been made in the
-	 * form.
-	 *
-	 * Constructs an array out of this component and the children to add it to
-	 * the history or to use when saving the form
-	 *
-	 * @returns {Array}
-	 */
-	getConfiguration: function() {
-		var historyConfiguration = {
-			hasDragAndDrop: this.hasDragAndDrop
-		};
-
-		if (this.items) {
-			historyConfiguration.items = [];
-			this.items.each(function(item, index, length) {
-				historyConfiguration.items.push(item.getConfiguration());
-			}, this);
-		}
-		return historyConfiguration;
-	}
-});
-
-Ext.reg('typo3-form-wizard-container', TYPO3.Form.Wizard.Container);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Content/Header.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Content/Header.js
deleted file mode 100644
index 3713f8506983842d95e1e5a7e39d9d6f0ead39a6..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Content/Header.js
+++ /dev/null
@@ -1,71 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Content');
-
-/**
- * The content HEADER element
- *
- * @class TYPO3.Form.Wizard.Elements.Content.Header
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Content.Header = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'header',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<tpl for="various">',
-				'<{headingSize} {[this.getAttributes(parent.attributes)]}>',
-				'{content}',
-				'</{type}>',
-			'</tpl>',
-		'</div>',
-		{
-			compiled: true,
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					"class": 'content-header',
-					dir: '',
-					id: '',
-					lang: '',
-					style: '',
-					title: ''
-				},
-				various: {
-					headingSize: 'h1',
-					content: TYPO3.l10n.localize('elements_header_content')
-				}
-			}
-		});
-		TYPO3.Form.Wizard.Elements.Content.Header.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-content-header', TYPO3.Form.Wizard.Elements.Content.Header);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Content/Textblock.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Content/Textblock.js
deleted file mode 100644
index 01f5ee01763c888b893c2229c4827e8d32ef4c3f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Content/Textblock.js
+++ /dev/null
@@ -1,70 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Content');
-
-/**
- * The content HEADER element
- *
- * @class TYPO3.Form.Wizard.Elements.Content.Header
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Content.Textblock = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} elementClass
-	 * An extra CSS class that will be added to this component's Element
-	 */
-	elementClass: 'textblock',
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<tpl for="various">',
-				'<div {[this.getAttributes(parent.attributes)]}>',
-				'{text:nl2br}',
-				'</{type}>',
-			'</tpl>',
-		'</div>',
-		{
-			compiled: true,
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				attributes: {
-					"class": '',
-					dir: '',
-					id: '',
-					lang: '',
-					style: '',
-					title: ''
-				},
-				various: {
-					text: TYPO3.l10n.localize('elements_textblock_content')
-				}
-			}
-		});
-		TYPO3.Form.Wizard.Elements.Content.Textblock.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-content-textblock', TYPO3.Form.Wizard.Elements.Content.Textblock);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Dummy.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Dummy.js
deleted file mode 100644
index b7ec2e97868abe1f69b6e2b66657fd7068b4f62e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Dummy.js
+++ /dev/null
@@ -1,69 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements');
-
-/**
- * The dummy element
- *
- * This type will be shown when there is no element in a container which will be
- * form or fieldset and will be removed when there is an element added.
- *
- * @class TYPO3.Form.Wizard.Elements.Dummy
- * @extends TYPO3.Form.Wizard.Elements
- */
-TYPO3.Form.Wizard.Elements.Dummy = Ext.extend(TYPO3.Form.Wizard.Elements, {
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'dummy',
-
-	/**
-	 * @cfg {String} cls
-	 * An optional extra CSS class that will be added to this component's
-	 * Element (defaults to ''). This can be useful for adding customized styles
-	 * to the component or any of its children using standard CSS rules.
-	 */
-	cls: 'dummy typo3-message message-information',
-
-	/**
-	 * @cfg {Object} configuration
-	 * The configuration of this element.
-	 * This object contains the configuration of this component. It will be
-	 * copied to the 'data' variable before rendering. 'data' is deleted after
-	 * rendering the xtemplate, so we need a copy.
-	 */
-	configuration: {
-		title: TYPO3.l10n.localize('elements_dummy_title'),
-		description: TYPO3.l10n.localize('elements_dummy_description')
-	},
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<p><strong>{title}</strong></p>',
-		'<p>{description}</p>'
-	),
-
-	/**
-	 * @cfg {Boolean} isEditable
-	 * Defines whether the element is editable. If the item is editable,
-	 * a button group with remove and edit buttons will be added to this element
-	 * and when the the element is clicked, an event is triggered to edit the
-	 * element. Some elements, like the dummy, don't need this.
-	 */
-	isEditable: false
-});
-
-Ext.reg('typo3-form-wizard-elements-dummy', TYPO3.Form.Wizard.Elements.Dummy);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Elements.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Elements.js
deleted file mode 100644
index d20e373721462d0455954b17f4324ef8a4de7250..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Elements.js
+++ /dev/null
@@ -1,301 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements');
-
-/**
- * Elements abstract
- *
- * @class TYPO3.Form.Wizard.Elements
- * @extends Ext.Container
- */
-TYPO3.Form.Wizard.Elements = Ext.extend(Ext.Container, {
-	/**
-	 * @cfg {Mixed} autoEl
-	 * A tag name or DomHelper spec used to create the Element which will
-	 * encapsulate this Component.
-	 */
-	autoEl: 'li',
-
-	/**
-	 * @cfg {String} cls
-	 * An optional extra CSS class that will be added to this component's
-	 * Element (defaults to ''). This can be useful for adding customized styles
-	 * to the component or any of its children using standard CSS rules.
-	 */
-	cls: 'formwizard-element',
-
-	/**
-	 * @cfg {Object} buttonGroup
-	 * Reference to the button group
-	 */
-	buttonGroup: null,
-
-	/**
-	 * @cfg {Boolean} isEditable
-	 * Defines whether the element is editable. If the item is editable,
-	 * a button group with remove and edit buttons will be added to this element
-	 * and when the the element is clicked, an event is triggered to edit the
-	 * element. Some elements, like the dummy, don't need this.
-	 */
-	isEditable: true,
-
-	/**
-	 * @cfg {Object} configuration
-	 * The configuration of this element.
-	 * This object contains the configuration of this component. It will be
-	 * copied to the 'data' variable before rendering. 'data' is deleted after
-	 * rendering the xtemplate, so we need a copy.
-	 */
-	configuration: {},
-
-	/**
-	 * Constructor
-	 */
-	initComponent: function() {
-		this.addEvents({
-			'configurationChange': true
-		});
-
-		var config = {};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Elements.superclass.initComponent.apply(this, arguments);
-
-			// Add the elementClass to the component
-		this.addClass(this.elementClass);
-
-			// Add the listener setactive for the element helper
-		TYPO3.Form.Wizard.Helpers.Element.on('setactive', this.toggleActive, this);
-
-			// Set the data before rendering
-		this.on('beforerender', this.beforeRender, this);
-
-			// Initialize events after rendering
-		this.on('afterrender', this.makeEditable, this);
-
-			// Remove event listeners after the detruction of this component
-		this.on('destroy', this.onDestroy, this);
-	},
-
-	/**
-	 * Copy this.configuration to this.data before rendering
-	 *
-	 * When using tpl together with data, the data variable will be deleted
-	 * after rendering the component. We do not want to lose this data, so we
-	 * store it in a different variable 'configuration' which will be copied to
-	 * data just before rendering
-	 *
-	 * All strings within the configuration object are HTML encoded first before
-	 * displaying
-	 *
-	 * @param component This component
-	 */
-	beforeRender: function(component) {
-		this.data = this.encodeConfiguration(this.configuration);
-	},
-
-	/**
-	 * Html encode all strings in the configuration of an element
-	 *
-	 * @param unencodedData The configuration object
-	 * @returns {Object}
-	 */
-	encodeConfiguration: function(unencodedData) {
-		var encodedData = {};
-
-		Ext.iterate(unencodedData, function (key, value, object) {
-			if (Ext.isString(value)) {
-				encodedData[key] = Ext.util.Format.htmlEncode(value);
-			} else if (Ext.isObject(value)) {
-				encodedData[key] = this.encodeConfiguration(value);
-			} else {
-				encodedData[key] = value;
-			}
-		}, this);
-
-		return encodedData;
-	},
-
-	/**
-	 * Add the buttongroup and a click event listener to this component when the
-	 * component is editable.
-	 */
-	makeEditable: function() {
-		if (this.isEditable) {
-			if (!this.buttonGroup) {
-				this.add({
-					xtype: 'typo3-form-wizard-buttongroup',
-					ref: 'buttonGroup'
-				});
-			}
-			this.el.un('click', this.setActive, this);
-			this.el.on('click', this.setActive, this);
-				// Add hover class. Normally this would be done with overCls,
-				// but this does not take bubbling (propagation) into account
-			this.el.hover(
-				function(){
-					Ext.fly(this).addClass('hover');
-				},
-				function(){
-					Ext.fly(this).removeClass('hover');
-				},
-				this.el,
-				{
-					stopPropagation: true
-				}
-			);
-		}
-	},
-
-	/**
-	 * Called on a click event of this component or when the element is added
-	 *
-	 * Tells the element helper that this component is set as the active one and
-	 * swallows the click event to prevent bubbling
-	 *
-	 * @param event
-	 * @param target
-	 * @param object
-	 */
-	setActive: function(event, target, object) {
-		TYPO3.Form.Wizard.Helpers.Element.setActive(this);
-		event.stopPropagation();
-	},
-
-	/**
-	 * Called when the element helper is firing the setactive event
-	 *
-	 * Adds an extra class 'active' to the element when the current component is
-	 * the active one, otherwise removes the class 'active' when this component
-	 * has this class
-	 * @param component
-	 */
-	toggleActive: function(component) {
-		if (this.isEditable) {
-			var element = this.getEl();
-
-			if (component && component.getId() == this.getId()) {
-				if (!element.hasClass('active')) {
-					element.addClass('active');
-				}
-			} else if (element.hasClass('active')) {
-				element.removeClass('active');
-			}
-		}
-	},
-
-	/**
-	 * Display a confirmation box when the delete button has been pressed.
-	 *
-	 * @param event
-	 * @param target
-	 * @param object
-	 */
-	confirmDeleteElement: function(event, target, object) {
-		Ext.MessageBox.confirm(
-			TYPO3.l10n.localize('elements_confirm_delete_title'),
-			TYPO3.l10n.localize('elements_confirm_delete_description'),
-			this.deleteElement,
-			this
-		);
-	},
-
-	/**
-	 * Delete the component when the yes button of the confirmation box has been
-	 * pressed.
-	 *
-	 * @param button The button which has been pressed (yes / no)
-	 */
-	deleteElement: function(button) {
-		if (button == 'yes') {
-			this.ownerCt.removeElement(this);
-		}
-	},
-
-	/**
-	 * Called by the parent of this component when a change has been made in the
-	 * form.
-	 *
-	 * Constructs an array out of this component and the children to add it to
-	 * the history or to use when saving the form
-	 *
-	 * @returns {Array}
-	 */
-	getConfiguration: function() {
-		var historyConfiguration = {
-			configuration: this.configuration,
-			isEditable: this.isEditable,
-			xtype: this.xtype
-		};
-
-		if (this.containerComponent) {
-			historyConfiguration.elementContainer = this.containerComponent.getConfiguration();
-		}
-		return historyConfiguration;
-	},
-
-	/**
-	 * Called when a configuration property has changed in the options tab
-	 *
-	 * Overwrites the configuration with the configuration from the form,
-	 * adds a new snapshot to the history and renders this component again.
-	 * @param formConfiguration
-	 */
-	setConfigurationValue: function(formConfiguration) {
-		Ext.merge(this.configuration, formConfiguration);
-		TYPO3.Form.Wizard.Helpers.History.setHistory();
-		this.rendered = false;
-		this.render();
-		this.doLayout();
-		this.fireEvent('configurationChange', this);
-	},
-
-	/**
-	 * Remove a validation rule from this element
-	 *
-	 * @param type
-	 */
-	removeValidationRule: function(type) {
-		if (this.configuration.validation[type]) {
-			delete this.configuration.validation[type];
-			TYPO3.Form.Wizard.Helpers.History.setHistory();
-			if (this.xtype != 'typo3-form-wizard-elements-basic-form') {
-				this.rendered = false;
-				this.render();
-				this.doLayout();
-			}
-		}
-	},
-
-	/**
-	 * Remove a filter from this element
-	 *
-	 * @param type
-	 */
-	removeFilter: function(type) {
-		if (this.configuration.filters[type]) {
-			delete this.configuration.filters[type];
-			TYPO3.Form.Wizard.Helpers.History.setHistory();
-			if (this.xtype != 'typo3-form-wizard-elements-basic-form') {
-				this.rendered = false;
-				this.render();
-				this.doLayout();
-			}
-		}
-	},
-
-	/**
-	 * Fires after the component is destroyed.
-	 *
-	 * Removes the listener for the 'setactive' event of the element helper.
-	 * Tells the element helper this element is destroyed and if set active,
-	 * it should be unset as active.
-	 */
-	onDestroy: function() {
-		TYPO3.Form.Wizard.Helpers.Element.un('setactive', this.toggleActive, this);
-		TYPO3.Form.Wizard.Helpers.Element.unsetActive(this);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements',TYPO3.Form.Wizard.Elements);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Predefined/CheckboxGroup.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Predefined/CheckboxGroup.js
deleted file mode 100644
index eb7bb3d25105a41d03b1ffe004a439dc7e468d40..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Predefined/CheckboxGroup.js
+++ /dev/null
@@ -1,154 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Predefined');
-
-/**
- * The predefined CHECKBOX GROUP element
- *
- * @class TYPO3.Form.Wizard.Elements.Predefined.CheckboxGroup
- * @extends TYPO3.Form.Wizard.Elements.Basic.Fieldset
- */
-TYPO3.Form.Wizard.Elements.Predefined.CheckboxGroup = Ext.extend(TYPO3.Form.Wizard.Elements.Basic.Fieldset, {
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<fieldset {[this.getAttributes(values.attributes)]}>',
-			'<tpl for="legend">',
-				'<tpl if="value">',
-					'<legend>{value}{[this.getMessage(parent.validation)]}</legend>',
-				'</tpl>',
-			'</tpl>',
-			'<ol></ol>',
-			'</fieldset>',
-		'</div>',
-		{
-			compiled: true,
-			getMessage: function(rules) {
-				var messageHtml = '';
-				var messages = [];
-				Ext.iterate(rules, function(rule, configuration) {
-					if (configuration.showMessage) {
-						messages.push(configuration.message);
-					}
-				}, this);
-
-				messageHtml = ' <em>' + messages.join(', ') + '</em>';
-				return messageHtml;
-
-			},
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Initialize the component
-	 */
-	initComponent: function() {
-		var config = {
-			elementContainer: {
-				hasDragAndDrop: false
-			},
-			configuration: {
-				attributes: {
-					"class": 'fieldset-subgroup',
-					dir: '',
-					id: '',
-					lang: '',
-					style: ''
-				},
-				legend: {
-					value: TYPO3.l10n.localize('elements_legend')
-				},
-				options: [
-					{
-						text: TYPO3.l10n.localize('elements_option_1'),
-						attributes: {
-							value: TYPO3.l10n.localize('elements_value_1')
-						}
-					},{
-						text: TYPO3.l10n.localize('elements_option_2'),
-						attributes: {
-							value: TYPO3.l10n.localize('elements_value_2')
-						}
-					},{
-						text: TYPO3.l10n.localize('elements_option_3'),
-						attributes: {
-							value: TYPO3.l10n.localize('elements_value_3')
-						}
-					}
-				],
-				various: {
-					name: ''
-				},
-				validation: {}
-			}
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(config, this.initialConfig));
-
-			// call parent
-		TYPO3.Form.Wizard.Elements.Predefined.CheckboxGroup.superclass.initComponent.apply(this, arguments);
-
-		this.on('configurationChange', this.rebuild, this);
-
-		this.on('afterrender', this.rebuild, this);
-	},
-
-	/**
-	 * Add the radio buttons to the containerComponent of this fieldset,
-	 * according to the configuration options.
-	 *
-	 * @param component
-	 */
-	rebuild: function(component) {
-		this.containerComponent.removeAll();
-		if (this.configuration.options.length > 0) {
-			var dummy = this.containerComponent.findById('dummy');
-			if (dummy) {
-				this.containerComponent.remove(dummy, true);
-			}
-			Ext.each(this.configuration.options, function(option, index, length) {
-				var checkbox = this.containerComponent.add({
-					xtype: 'typo3-form-wizard-elements-basic-checkbox',
-					isEditable: false,
-					cls: ''
-				});
-				var optionValue = '';
-				if (option.attributes && option.attributes.value) {
-					optionValue = option.attributes.value;
-				}
-				var checkboxConfiguration = {
-					label: {
-						value: option.text
-					},
-					attributes: {
-						value: optionValue
-					}
-				};
-				if (
-					option.attributes &&
-					option.attributes.selected &&
-					option.attributes.selected == 'selected'
-				) {
-					checkboxConfiguration.attributes.checked = 'checked';
-				}
-				Ext.merge(checkbox.configuration, checkboxConfiguration);
-			}, this);
-			this.containerComponent.doLayout();
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-predefined-checkboxgroup', TYPO3.Form.Wizard.Elements.Predefined.CheckboxGroup);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Predefined/Email.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Predefined/Email.js
deleted file mode 100644
index 84eb97adfc56040705c53585de83740f03b2278b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Predefined/Email.js
+++ /dev/null
@@ -1,46 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Predefined');
-
-/**
- * The predefined EMAIL element
- *
- * @class TYPO3.Form.Wizard.Elements.Predefined.Email
- * @extends TYPO3.Form.Wizard.Elements.Basic.Textline
- */
-TYPO3.Form.Wizard.Elements.Predefined.Email = Ext.extend(TYPO3.Form.Wizard.Elements.Basic.Textline, {
-	/**
-	 * Initialize the component
-	 */
-	initComponent: function() {
-		var config = {
-			configuration: {
-				attributes: {
-					name: 'email',
-					type: 'email'
-				},
-				label: {
-					value: TYPO3.l10n.localize('elements_label_email')
-				},
-				validation: {
-					required: {
-						showMessage: 1,
-						message: TYPO3.l10n.localize('tx_form_system_validate_required.message'),
-						error: TYPO3.l10n.localize('tx_form_system_validate_required.error')
-					},
-					email: {
-						showMessage: 1,
-						message: TYPO3.l10n.localize('tx_form_system_validate_email.message'),
-						error: TYPO3.l10n.localize('tx_form_system_validate_email.error')
-					}
-				}
-			}
-		};
-
-			// MERGE config
-		Ext.merge(this, config);
-
-			// call parent
-		TYPO3.Form.Wizard.Elements.Predefined.Email.superclass.initComponent.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-predefined-email', TYPO3.Form.Wizard.Elements.Predefined.Email);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Predefined/Name.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Predefined/Name.js
deleted file mode 100644
index 8cc1437d3b3d636f72f6f1da9c6c7c45be7ad954..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Predefined/Name.js
+++ /dev/null
@@ -1,156 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Predefined');
-
-/**
- * The predefined NAME element
- *
- * @class TYPO3.Form.Wizard.Elements.Predefined.Name
- * @extends TYPO3.Form.Wizard.Elements.Basic.Fieldset
- */
-TYPO3.Form.Wizard.Elements.Predefined.Name = Ext.extend(TYPO3.Form.Wizard.Elements.Basic.Fieldset, {
-	/**
-	 * Initialize the component
-	 */
-	initComponent: function() {
-		var config = {
-			configuration: {
-				attributes: {
-					"class": 'predefined-name fieldset-subgroup fieldset-horizontal label-below',
-					dir: '',
-					id: '',
-					lang: '',
-					style: ''
-				},
-				legend: {
-					value: TYPO3.l10n.localize('elements_legend_name')
-				},
-				various: {
-					prefix: true,
-					suffix: true,
-					middleName: true
-				}
-			}
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(config, this.initialConfig));
-
-			// call parent
-		TYPO3.Form.Wizard.Elements.Predefined.Name.superclass.initComponent.apply(this, arguments);
-
-		this.on('configurationChange', this.rebuild, this);
-
-		this.on('afterrender', this.rebuild, this);
-	},
-
-	/**
-	 * Add the fields to the containerComponent of this fieldset,
-	 * according to the configuration options.
-	 *
-	 * @param component
-	 */
-	rebuild: function(component) {
-		this.containerComponent.removeAll();
-		var dummy = this.containerComponent.findById('dummy');
-		if (dummy) {
-			this.containerComponent.remove(dummy, true);
-		}
-		if (this.configuration.various.prefix) {
-			var prefix = this.containerComponent.add({
-				xtype: 'typo3-form-wizard-elements-basic-textline',
-				isEditable: false,
-				cls: '',
-				configuration: {
-					label: {
-						value: TYPO3.l10n.localize('elements_label_prefix')
-					},
-					attributes: {
-						name: 'prefix',
-						size: 4
-					},
-					layout: 'back'
-				}
-			});
-		}
-		var firstName = this.containerComponent.add({
-			xtype: 'typo3-form-wizard-elements-basic-textline',
-			isEditable: false,
-			cls: '',
-			configuration: {
-				label: {
-					value: TYPO3.l10n.localize('elements_label_firstname')
-				},
-				attributes: {
-					name: 'firstName',
-					size: 10
-				},
-				layout: 'back',
-				validation: {
-					required: {
-						showMessage: true,
-						message: '*',
-						error: 'Required'
-					}
-				}
-			}
-		});
-		if (this.configuration.various.middleName) {
-			var middleName = this.containerComponent.add({
-				xtype: 'typo3-form-wizard-elements-basic-textline',
-				isEditable: false,
-				cls: '',
-				configuration: {
-					label: {
-						value: TYPO3.l10n.localize('elements_label_middlename')
-					},
-					attributes: {
-						name: 'middleName',
-						size: 6
-					},
-					layout: 'back'
-				}
-			});
-		}
-		var lastName = this.containerComponent.add({
-			xtype: 'typo3-form-wizard-elements-basic-textline',
-			isEditable: false,
-			cls: '',
-			configuration: {
-				label: {
-					value: TYPO3.l10n.localize('elements_label_lastname')
-				},
-				attributes: {
-					name: 'lastName',
-					size: 15
-				},
-				layout: 'back',
-				validation: {
-					required: {
-						showMessage: true,
-						message: '*',
-						error: 'Required'
-					}
-				}
-			}
-		});
-		if (this.configuration.various.suffix) {
-			var suffix = this.containerComponent.add({
-				xtype: 'typo3-form-wizard-elements-basic-textline',
-				isEditable: false,
-				cls: '',
-				configuration: {
-					label: {
-						value: TYPO3.l10n.localize('elements_label_suffix')
-					},
-					attributes: {
-						name: 'suffix',
-						size: 4
-					},
-					layout: 'back'
-				}
-			});
-		}
-		this.containerComponent.doLayout();
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-predefined-name', TYPO3.Form.Wizard.Elements.Predefined.Name);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Predefined/RadioGroup.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Predefined/RadioGroup.js
deleted file mode 100644
index f93d1470fdc8120d5dea68c221bb6154415dd079..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Elements/Predefined/RadioGroup.js
+++ /dev/null
@@ -1,154 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Elements.Predefined');
-
-/**
- * The predefined RADIO GROUP element
- *
- * @class TYPO3.Form.Wizard.Elements.Predefined.RadioGroup
- * @extends TYPO3.Form.Wizard.Elements.Basic.Fieldset
- */
-TYPO3.Form.Wizard.Elements.Predefined.RadioGroup = Ext.extend(TYPO3.Form.Wizard.Elements.Basic.Fieldset, {
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<div class="overflow-hidden">',
-			'<fieldset {[this.getAttributes(values.attributes)]}>',
-			'<tpl for="legend">',
-				'<tpl if="value">',
-					'<legend>{value}{[this.getMessage(parent.validation)]}</legend>',
-				'</tpl>',
-			'</tpl>',
-			'<ol></ol>',
-			'</fieldset>',
-		'</div>',
-		{
-			compiled: true,
-			getMessage: function(rules) {
-				var messageHtml = '';
-				var messages = [];
-				Ext.iterate(rules, function(rule, configuration) {
-					if (configuration.showMessage) {
-						messages.push(configuration.message);
-					}
-				}, this);
-
-				messageHtml = ' <em>' + messages.join(', ') + '</em>';
-				return messageHtml;
-
-			},
-			getAttributes: function(attributes) {
-				var attributesHtml = '';
-				Ext.iterate(attributes, function(key, value) {
-					if (value) {
-						attributesHtml += key + '="' + value + '" ';
-					}
-				}, this);
-				return attributesHtml;
-			}
-		}
-	),
-
-	/**
-	 * Initialize the component
-	 */
-	initComponent: function() {
-		var config = {
-			elementContainer: {
-				hasDragAndDrop: false
-			},
-			configuration: {
-				attributes: {
-					"class": 'fieldset-subgroup',
-					dir: '',
-					id: '',
-					lang: '',
-					style: ''
-				},
-				legend: {
-					value: TYPO3.l10n.localize('elements_legend')
-				},
-				options: [
-					{
-						text: TYPO3.l10n.localize('elements_option_1'),
-						attributes: {
-							value: TYPO3.l10n.localize('elements_value_1')
-						}
-					},{
-						text: TYPO3.l10n.localize('elements_option_2'),
-						attributes: {
-							value: TYPO3.l10n.localize('elements_value_2')
-						}
-					},{
-						text: TYPO3.l10n.localize('elements_option_3'),
-						attributes: {
-							value: TYPO3.l10n.localize('elements_value_3')
-						}
-					}
-				],
-				various: {
-					name: ''
-				},
-				validation: {}
-			}
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(config, this.initialConfig));
-
-			// call parent
-		TYPO3.Form.Wizard.Elements.Predefined.RadioGroup.superclass.initComponent.apply(this, arguments);
-
-		this.on('configurationChange', this.rebuild, this);
-
-		this.on('afterrender', this.rebuild, this);
-	},
-
-	/**
-	 * Add the radio buttons to the containerComponent of this fieldset,
-	 * according to the configuration options.
-	 *
-	 * @param component
-	 */
-	rebuild: function(component) {
-		this.containerComponent.removeAll();
-		if (this.configuration.options.length > 0) {
-			var dummy = this.containerComponent.findById('dummy');
-			if (dummy) {
-				this.containerComponent.remove(dummy, true);
-			}
-			Ext.each(this.configuration.options, function(option, index, length) {
-				var radio = this.containerComponent.add({
-					xtype: 'typo3-form-wizard-elements-basic-radio',
-					isEditable: false,
-					cls: ''
-				});
-				var optionValue = '';
-				if (option.attributes && option.attributes.value) {
-					optionValue = option.attributes.value;
-				}
-				var radioConfiguration = {
-					label: {
-						value: option.text
-					},
-					attributes: {
-						value: optionValue
-					}
-				};
-				if (
-					option.attributes &&
-					option.attributes.selected &&
-					option.attributes.selected == 'selected'
-				) {
-					radioConfiguration.attributes.checked = 'checked';
-				}
-				Ext.merge(radio.configuration, radioConfiguration);
-			}, this);
-			this.containerComponent.doLayout();
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-elements-predefined-radiogroup', TYPO3.Form.Wizard.Elements.Predefined.RadioGroup);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Helpers/Element.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Helpers/Element.js
deleted file mode 100644
index 2b38ef26f9632f36a5282170eb5e704007cafbaf..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Helpers/Element.js
+++ /dev/null
@@ -1,71 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Helpers');
-
-TYPO3.Form.Wizard.Helpers.Element = Ext.extend(Ext.util.Observable, {
-	/**
-	 * @cfg {Object} active
-	 * The current active form element
-	 */
-	active: null,
-
-	/**
-	 * Constructor
-	 *
-	 * @param config
-	 */
-	constructor: function(config){
-			// Adds the specified events to the list of events which this Observable may fire.
-		this.addEvents({
-			'setactive': true
-		});
-
-			// Call our superclass constructor to complete construction process.
-		TYPO3.Form.Wizard.Helpers.Element.superclass.constructor.call(this, config);
-	},
-
-	/**
-	 * Fires the setactive event when a component is set as active
-	 *
-	 * @param component
-	 */
-	setActive: function(component) {
-		var optionsTabIsValid = Ext.getCmp('formwizard-left-options').tabIsValid();
-
-		if (optionsTabIsValid) {
-			if (component == this.active) {
-				this.active = null;
-			} else {
-				this.active = component;
-			}
-			this.fireEvent('setactive', this.active);
-		} else {
-			Ext.MessageBox.show({
-				title: TYPO3.l10n.localize('options_error'),
-				msg: TYPO3.l10n.localize('options_error_message'),
-				icon: Ext.MessageBox.ERROR,
-				buttons: Ext.MessageBox.OK
-			});
-		}
-	},
-
-	/**
-	 * Fires the setactive event when a component is unset.
-	 *
-	 * This means when the element is destroyed or when the form is reloaded
-	 * using undo or redo
-	 *
-	 * @param component
-	 */
-	unsetActive: function(component) {
-		if (
-			this.active && (
-				(component && component.getId() == this.active.getId()) ||
-				!component
-			)
-		){
-			this.active = null;
-			this.fireEvent('setactive');
-		}
-	}
-});
-
-TYPO3.Form.Wizard.Helpers.Element = new TYPO3.Form.Wizard.Helpers.Element();
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Helpers/History.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Helpers/History.js
deleted file mode 100644
index a92be63cc7e88fa8b5715d020917654f822c099f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Helpers/History.js
+++ /dev/null
@@ -1,139 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Helpers');
-
-TYPO3.Form.Wizard.Helpers.History = Ext.extend(Ext.util.Observable, {
-	/**
-	 * @cfg {Integer} maximum
-	 * Maximum steps to go back or forward in history
-	 */
-	maximum: 20,
-
-	/**
-	 * @cfg {Integer} marker
-	 * The current step in the history
-	 */
-	marker: 0,
-
-	/**
-	 * @cfg {Array} history
-	 * Holds the configuration for each step in history
-	 */
-	history: [],
-
-	/**
-	 * #cfg {String} undoButtonId
-	 * The id of the undo button
-	 */
-	undoButtonId: 'formwizard-history-undo',
-
-	/**
-	 * #cfg {String} redoButtonId
-	 * The id of the redo button
-	 */
-	redoButtonId: 'formwizard-history-redo',
-
-	/**
-	 * Constructor
-	 *
-	 * @param config
-	 */
-	constructor: function(config){
-			// Call our superclass constructor to complete construction process.
-		TYPO3.Form.Wizard.Helpers.History.superclass.constructor.call(this, config);
-	},
-
-	/**
-	 * Called when a component is added to a container or there was a change in
-	 * one of the form components
-	 *
-	 * Gets the configuration of all (nested) components, starting at
-	 * viewport-right, and adds this configuration to the history
-	 *
-	 * @returns {void}
-	 */
-	setHistory: function() {
-		var configuration = Ext.getCmp('formwizard-right').getConfiguration();
-		this.addToHistory(configuration);
-	},
-
-	/**
-	 * Add a snapshot to the history
-	 *
-	 * @param {Object} configuration The form configuration snapshot
-	 * @return {void}
-	 */
-	addToHistory: function(configuration) {
-		while (this.history.length > this.marker) {
-			this.history.pop();
-		}
-		this.history.push(Ext.encode(configuration));
-		while (this.history.length > this.maximum) {
-			this.history.shift();
-		}
-		this.marker = this.history.length;
-	},
-
-	/**
-	 * Get the current snapshot from the history
-	 *
-	 * @return {Object} The current snapshot
-	 */
-	refresh: function() {
-		var refreshObject = Ext.decode(this.history[this.marker-1]);
-		Ext.getCmp('formwizard-right').loadConfiguration(refreshObject);
-	},
-
-	/**
-	 * Get the previous snapshot from the history if available
-	 *
-	 * Unsets the active element, because this element will not be available anymore
-	 *
-	 * @return {Object} The previous snapshot
-	 */
-	undo: function() {
-		if (this.marker >= 1) {
-			this.marker--;
-			var undoObject = Ext.decode(this.history[this.marker-1]);
-			Ext.getCmp('formwizard-right').loadConfiguration(undoObject);
-			TYPO3.Form.Wizard.Helpers.Element.unsetActive();
-		}
-	},
-
-	/**
-	 * Get the next snapshot from the history if available
-	 *
-	 * Unsets the active element, because this element will not be available anymore
-	 *
-	 * @return {Object} The next snapshot
-	 */
-	redo: function() {
-		if (this.history.length > this.marker) {
-			this.marker++;
-			var redoObject = Ext.decode(this.history[this.marker-1]);
-			Ext.getCmp('formwizard-right').loadConfiguration(redoObject);
-			TYPO3.Form.Wizard.Helpers.Element.unsetActive();
-		}
-	},
-
-	/**
-	 * Turn the undo/redo buttons on or off
-	 * according to marker in the history
-	 *
-	 * @return {void}
-	 */
-	buttons: function() {
-		var undoButton = Ext.get(this.undoButtonId);
-		var redoButton = Ext.get(this.redoButtonId);
-		if (this.marker > 1) {
-			undoButton.show();
-		} else {
-			undoButton.hide();
-		}
-		if (this.history.length > this.marker) {
-			redoButton.show();
-		} else {
-			redoButton.hide();
-		}
-	}
-});
-
-TYPO3.Form.Wizard.Helpers.History = new TYPO3.Form.Wizard.Helpers.History();
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.form.FakeFormPanel.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.form.FakeFormPanel.js
deleted file mode 100644
index dbbc63aed3583bd0e92c959d85c783872e4b4c43..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.form.FakeFormPanel.js
+++ /dev/null
@@ -1,35 +0,0 @@
-Ext.ns('Ext.ux.form');
-
-/**
- * @class Ext.ux.form.FakeFormPanel
- * @extends Ext.form.FormPanel
- *
- * @xtype typo3-form-wizard-fakeformpanel
- */
-Ext.ux.form.FakeFormPanel = Ext.extend(Ext.form.FormPanel, {
-
-    initComponent : function(){
-        this.form = this.createForm();
-        Ext.FormPanel.superclass.initComponent.call(this);
-
-        this.bodyCfg = {
-            tag: 'div',
-            cls: this.baseCls + '-body',
-            method : this.method || 'POST',
-            id : this.formId || Ext.id()
-        };
-        if(this.fileUpload) {
-            this.bodyCfg.enctype = 'multipart/form-data';
-        }
-        this.initItems();
-
-        this.addEvents(
-            'clientvalidation'
-        );
-
-        this.relayEvents(this.form, ['beforeaction', 'actionfailed', 'actioncomplete']);
-    }
-
-});
-
-Ext.reg('typo3-form-wizard-fakeformpanel', Ext.ux.form.FakeFormPanel);
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.form.ValueCheckbox.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.form.ValueCheckbox.js
deleted file mode 100644
index b40f821dc30b2baa5f9034260ffa273d0ea508d8..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.form.ValueCheckbox.js
+++ /dev/null
@@ -1,21 +0,0 @@
-Ext.ns('Ext.ux.form');
-
-/**
- * @class Ext.ux.form.ValueCheckbox
- * @extends Ext.form.Checkbox
- * getValue returns inputValue when checked
- *
- * @see TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Attributes.initComponent
- * @xtype typo3-form-wizard-valuecheckbox
- */
-Ext.ux.form.ValueCheckbox = Ext.extend(Ext.form.Checkbox, {
-
-	getValue : function(){
-		var checked = Ext.ux.form.ValueCheckbox.superclass.getValue.call(this);
-		if(this.inputValue !== undefined && checked)
-			return this.inputValue;
-		return checked;
-	}
-});
-
-Ext.reg('typo3-form-wizard-valuecheckbox', Ext.ux.form.ValueCheckbox);
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.form.spinnerfield.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.form.spinnerfield.js
deleted file mode 100644
index 92765c60c004a6006bc724e92660b7e2b082cdb5..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.form.spinnerfield.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/*!
- * Ext JS Library 3.3.1
- * Copyright(c) 2006-2010 Sencha Inc.
- * licensing@sencha.com
- * http://www.sencha.com/license
- */
-Ext.ns('Ext.ux.form');
-
-/**
- * @class Ext.ux.form.SpinnerField
- * @extends Ext.form.NumberField
- * Creates a field utilizing Ext.ux.Spinner
- * @xtype spinnerfield
- */
-Ext.ux.form.SpinnerField = Ext.extend(Ext.form.NumberField, {
-	actionMode: 'wrap',
-	deferHeight: true,
-	autoSize: Ext.emptyFn,
-	// onBlur function shall use the inherited handler function
-	// onBlur: Ext.emptyFn,
-	adjustSize: Ext.BoxComponent.prototype.adjustSize,
-
-	constructor: function(config) {
-		var spinnerConfig = Ext.copyTo({}, config, 'incrementValue,alternateIncrementValue,accelerate,defaultValue,triggerClass,splitterClass');
-
-		var spl = this.spinner = new Ext.ux.Spinner(spinnerConfig);
-
-		var plugins = config.plugins
-			? (Ext.isArray(config.plugins)
-				? config.plugins.push(spl)
-				: [config.plugins, spl])
-			: spl;
-
-		Ext.ux.form.SpinnerField.superclass.constructor.call(this, Ext.apply(config, {plugins: plugins}));
-	},
-
-	// private
-	getResizeEl: function(){
-		return this.wrap;
-	},
-
-	// private
-	getPositionEl: function(){
-		return this.wrap;
-	},
-
-	// private
-	alignErrorIcon: function(){
-		if (this.wrap) {
-			this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
-		}
-	},
-
-	validateBlur: function(){
-		return true;
-	}
-});
-
-Ext.reg('spinnerfield', Ext.ux.form.SpinnerField);
-
-//backwards compat
-Ext.form.SpinnerField = Ext.ux.form.SpinnerField;
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.form.textfieldsubmit.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.form.textfieldsubmit.js
deleted file mode 100644
index 8c22516c7af4bf558da2ee94f13c4bbeaf2c0ddb..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.form.textfieldsubmit.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/*!
- * Ext JS Library 3.3.1
- * Copyright(c) 2006-2010 Sencha Inc.
- * licensing@sencha.com
- * http://www.sencha.com/license
- */
-Ext.ns('Ext.ux.form');
-
-/**
- * @class Ext.ux.form.TextFieldSubmit
- * @extends Ext.form.TriggerField
- * Creates a text field with a submit trigger button
- * @xtype textfieldsubmit
- */
-Ext.ux.form.TextFieldSubmit = Ext.extend(Ext.form.TriggerField, {
-	hideTrigger: true,
-
-	triggerClass: 'x-form-submit-trigger',
-
-	enableKeyEvents: true,
-
-	onTriggerClick: function() {
-		this.setHideTrigger(true);
-		if (this.isValid()) {
-			this.fireEvent('triggerclick', this);
-		} else {
-			this.setValue(this.startValue);
-		}
-	},
-
-	initEvents: function() {
-		Ext.ux.form.TextFieldSubmit.superclass.initEvents.call(this);
-		this.on('keyup', function(field, event) {
-			if (event.getKey() != event.ENTER && this.isValid()) {
-				this.setHideTrigger(false);
-			} else {
-				this.setHideTrigger(true);
-			}
-		});
-		this.on('keypress', function(field, event) {
-			if (event.getKey() == event.ENTER) {
-				event.stopEvent();
-				this.onTriggerClick();
-			}
-		}, this);
-	}
-});
-
-Ext.reg('textfieldsubmit', Ext.ux.form.TextFieldSubmit);
-
-//backwards compat
-Ext.form.TextFieldSubmit = Ext.ux.form.TextFieldSubmit;
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.grid.CheckColumn.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.grid.CheckColumn.js
deleted file mode 100644
index 806364d47a23addc640a04b2e0a1c44dd11915af..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.grid.CheckColumn.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/*!
- * Ext JS Library 3.1.1
- * Copyright(c) 2006-2010 Ext JS, LLC
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
-Ext.ns('Ext.ux.grid');
-
-/**
- * @class Ext.ux.grid.CheckColumn
- * @extends Object
- * GridPanel plugin to add a column with check boxes to a grid.
- * <p>Example usage:</p>
- * <pre><code>
-// create the column
-var checkColumn = new Ext.grid.CheckColumn({
-   header: 'Indoor?',
-   dataIndex: 'indoor',
-   id: 'check',
-   width: 55
-});
-
-// add the column to the column model
-var cm = new Ext.grid.ColumnModel([{
-	   header: 'Foo',
-	   ...
-	},
-	checkColumn
-]);
-
-// create the grid
-var grid = new Ext.grid.EditorGridPanel({
-	...
-	cm: cm,
-	plugins: [checkColumn], // include plugin
-	...
-});
- * </code></pre>
- * In addition to storing a Boolean value within the record data, this
- * class toggles a css class between <tt>'x-grid3-check-col'</tt> and
- * <tt>'x-grid3-check-col-on'</tt> to alter the background image used for
- * a column.
- */
-Ext.ux.grid.CheckColumn = function(config){
-	Ext.apply(this, config);
-	if(!this.id){
-		this.id = Ext.id();
-	}
-	this.renderer = this.renderer.createDelegate(this);
-};
-
-Ext.ux.grid.CheckColumn.prototype ={
-	init : function(grid){
-		this.grid = grid;
-		this.grid.on('render', function(){
-			var view = this.grid.getView();
-			view.mainBody.on('mousedown', this.onMouseDown, this);
-		}, this);
-	},
-
-	onMouseDown : function(e, t){
-		if(Ext.fly(t).hasClass(this.createId())){
-			e.stopEvent();
-			var index = this.grid.getView().findRowIndex(t);
-			var record = this.grid.store.getAt(index);
-			record.set(this.dataIndex, !record.data[this.dataIndex]);
-		}
-	},
-
-	renderer : function(v, p, record){
-		p.css += ' x-grid3-check-col-td';
-		return String.format('<div class="x-grid3-check-col{0} {1}">&#160;</div>', v ? '-on' : '', this.createId());
-	},
-
-	createId : function(){
-		return 'x-grid3-cc-' + this.id;
-	}
-};
-
-// register ptype
-Ext.preg('checkcolumn', Ext.ux.grid.CheckColumn);
-
-// backwards compat
-Ext.grid.CheckColumn = Ext.ux.grid.CheckColumn;
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.grid.ItemDeleter.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.grid.ItemDeleter.js
deleted file mode 100644
index bbc94fe92a4381006e2d8848092ff72df4aae656..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.grid.ItemDeleter.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- */
-Ext.ns('Ext.ux.grid');
-
-Ext.ux.grid.ItemDeleter = Ext.extend(Ext.grid.RowSelectionModel, {
-	width: 25,
-	sortable: false,
-	dataIndex: 0, // this is needed, otherwise there will be an error
-
-	menuDisabled: true,
-	fixed: true,
-	id: 'deleter',
-	header: TYPO3.l10n.localize('fieldoptions_delete'),
-
-	initEvents: function(){
-		Ext.ux.grid.ItemDeleter.superclass.initEvents.call(this);
-		this.grid.on('cellclick', function(grid, rowIndex, columnIndex, e){
-			if(columnIndex==grid.getColumnModel().getIndexById('deleter')) {
-				var record = grid.getStore().getAt(rowIndex);
-				grid.getStore().remove(record);
-				grid.getView().refresh();
-			}
-		});
-	},
-
-	renderer: function(v, p, record, rowIndex){
-		return '<div class="remove">&nbsp;</div>';
-	}
-});
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.grid.SingleSelectCheckColumn.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.grid.SingleSelectCheckColumn.js
deleted file mode 100644
index 6292fe6fae949bbbda313e149ee491808f090ba1..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.grid.SingleSelectCheckColumn.js
+++ /dev/null
@@ -1,15 +0,0 @@
-Ext.ux.grid.SingleSelectCheckColumn = Ext.extend(Ext.ux.grid.CheckColumn, {
-	onMouseDown : function(e, t){
-		if(Ext.fly(t).hasClass('x-grid3-cc-'+this.id)){
-			e.stopEvent();
-			var index = this.grid.getView().findRowIndex(t),
-				dataIndex = this.dataIndex;
-			this.grid.store.each(function(record, i){
-				var value = (i == index && record.get(dataIndex) != true);
-				if(value != record.get(dataIndex)){
-					record.set(dataIndex, value);
-				}
-			});
-		}
-	}
-});
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.isemptyobject.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.isemptyobject.js
deleted file mode 100644
index 12235642ce3a9956648121372677c1168feb08f2..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.isemptyobject.js
+++ /dev/null
@@ -1,8 +0,0 @@
-Ext.apply(Ext, {
-	isEmptyObject: function(o) {
-		for(var p in o) {
-			return false;
-		};
-		return true;
-	}
-});
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.merge.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.merge.js
deleted file mode 100644
index 70b66c201d8e2da025853517712256ec0ce85ae5..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.merge.js
+++ /dev/null
@@ -1,26 +0,0 @@
-Ext.apply(Ext, {
-	merge: function(o, c) {
-		if (o && c && typeof c == 'object') {
-			for (var p in c){
-				if ((typeof o[p] == 'object') && (typeof c[p] == 'object')) {
-					Ext.merge(o[p], c[p]);
-				} else {
-					o[p] = c[p];
-				}
-			}
-		}
-		return o;
-	},
-	mergeIf: function(o, c) {
-		if (o && c && typeof c == 'object') {
-			for (var p in c){
-				if ((typeof o[p] == 'object') && (typeof c[p] == 'object')) {
-					Ext.mergeIf(o[p], c[p]);
-				} else if (typeof o[p] == 'undefined') {
-					o[p] = c[p];
-				}
-			}
-		}
-		return o;
-	}
-});
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.spinner.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.spinner.js
deleted file mode 100644
index edd7d1efd1a57e1fa09e9239c133a24f43c073be..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Ux/Ext.ux.spinner.js
+++ /dev/null
@@ -1,443 +0,0 @@
-/*!
- * Ext JS Library 3.3.1
- * Copyright(c) 2006-2010 Sencha Inc.
- * licensing@sencha.com
- * http://www.sencha.com/license
- */
-/**
- * @class Ext.ux.Spinner
- * @extends Ext.util.Observable
- * Creates a Spinner control utilized by Ext.ux.form.SpinnerField
- */
-Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
-	incrementValue: 1,
-	alternateIncrementValue: 5,
-	triggerClass: 'x-form-spinner-trigger',
-	splitterClass: 'x-form-spinner-splitter',
-	alternateKey: Ext.EventObject.shiftKey,
-	defaultValue: 0,
-	accelerate: false,
-
-	constructor: function(config){
-		Ext.ux.Spinner.superclass.constructor.call(this, config);
-		Ext.apply(this, config);
-		this.mimicing = false;
-	},
-
-	init: function(field){
-		this.field = field;
-
-		field.afterMethod('onRender', this.doRender, this);
-		field.afterMethod('onEnable', this.doEnable, this);
-		field.afterMethod('onDisable', this.doDisable, this);
-		field.afterMethod('afterRender', this.doAfterRender, this);
-		field.afterMethod('onResize', this.doResize, this);
-		field.afterMethod('onFocus', this.doFocus, this);
-		field.beforeMethod('onDestroy', this.doDestroy, this);
-	},
-
-	doRender: function(ct, position){
-		var el = this.el = this.field.getEl();
-		var f = this.field;
-
-		if (!f.wrap) {
-			f.wrap = this.wrap = el.wrap({
-				cls: "x-form-field-wrap"
-			});
-		}
-		else {
-			this.wrap = f.wrap.addClass('x-form-field-wrap');
-		}
-
-		this.trigger = this.wrap.createChild({
-			tag: "img",
-			src: Ext.BLANK_IMAGE_URL,
-			cls: "x-form-trigger " + this.triggerClass
-		});
-
-		if (!f.width) {
-			this.wrap.setWidth(el.getWidth() + this.trigger.getWidth());
-		}
-
-		this.splitter = this.wrap.createChild({
-			tag: 'div',
-			cls: this.splitterClass,
-			style: 'width:13px; height:2px;'
-		});
-		this.splitter.setRight((Ext.isIE) ? 1 : 2).setTop(10).show();
-
-		this.proxy = this.trigger.createProxy('', this.splitter, true);
-		this.proxy.addClass("x-form-spinner-proxy");
-		this.proxy.setStyle('left', '0px');
-		this.proxy.setSize(14, 1);
-		this.proxy.hide();
-		this.dd = new Ext.dd.DDProxy(this.splitter.dom.id, "SpinnerDrag", {
-			dragElId: this.proxy.id
-		});
-
-		this.initTrigger();
-		this.initSpinner();
-	},
-
-	doAfterRender: function(){
-		var y;
-		if (Ext.isIE && this.el.getY() != (y = this.trigger.getY())) {
-			this.el.position();
-			this.el.setY(y);
-		}
-	},
-
-	doEnable: function(){
-		if (this.wrap) {
-			this.disabled = false;
-			this.wrap.removeClass(this.field.disabledClass);
-		}
-	},
-
-	doDisable: function(){
-		if (this.wrap) {
-			this.disabled = true;
-			this.wrap.addClass(this.field.disabledClass);
-			this.el.removeClass(this.field.disabledClass);
-		}
-	},
-
-	doResize: function(w, h){
-		if (typeof w == 'number') {
-			this.el.setWidth(w - this.trigger.getWidth());
-		}
-		this.wrap.setWidth(this.el.getWidth() + this.trigger.getWidth());
-	},
-
-	doFocus: function(){
-		if (!this.mimicing) {
-			this.wrap.addClass('x-trigger-wrap-focus');
-			this.mimicing = true;
-			Ext.get(Ext.isIE ? document.body : document).on("mousedown", this.mimicBlur, this, {
-				delay: 10
-			});
-			this.el.on('keydown', this.checkTab, this);
-		}
-	},
-
-	// private
-	checkTab: function(e){
-		if (e.getKey() == e.TAB) {
-			this.triggerBlur();
-		}
-	},
-
-	// private
-	mimicBlur: function(e){
-		if (!this.wrap.contains(e.target) && this.field.validateBlur(e)) {
-			this.triggerBlur();
-		}
-	},
-
-	// private
-	triggerBlur: function(){
-		this.mimicing = false;
-		Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this);
-		this.el.un("keydown", this.checkTab, this);
-		this.field.beforeBlur();
-		this.wrap.removeClass('x-trigger-wrap-focus');
-		this.field.onBlur.call(this.field);
-	},
-
-	initTrigger: function(){
-		this.trigger.addClassOnOver('x-form-trigger-over');
-		this.trigger.addClassOnClick('x-form-trigger-click');
-	},
-
-	initSpinner: function(){
-		this.field.addEvents({
-			'spin': true,
-			'spinup': true,
-			'spindown': true
-		});
-
-		this.keyNav = new Ext.KeyNav(this.el, {
-			"up": function(e){
-				e.preventDefault();
-				this.onSpinUp();
-			},
-
-			"down": function(e){
-				e.preventDefault();
-				this.onSpinDown();
-			},
-
-			"pageUp": function(e){
-				e.preventDefault();
-				this.onSpinUpAlternate();
-			},
-
-			"pageDown": function(e){
-				e.preventDefault();
-				this.onSpinDownAlternate();
-			},
-
-			scope: this
-		});
-
-		this.repeater = new Ext.util.ClickRepeater(this.trigger, {
-			accelerate: this.accelerate
-		});
-		this.field.mon(this.repeater, "click", this.onTriggerClick, this, {
-			preventDefault: true
-		});
-
-		this.field.mon(this.trigger, {
-			mouseover: this.onMouseOver,
-			mouseout: this.onMouseOut,
-			mousemove: this.onMouseMove,
-			mousedown: this.onMouseDown,
-			mouseup: this.onMouseUp,
-			scope: this,
-			preventDefault: true
-		});
-
-		this.field.mon(this.wrap, "mousewheel", this.handleMouseWheel, this);
-
-		this.dd.setXConstraint(0, 0, 10);
-		this.dd.setYConstraint(1500, 1500, 10);
-		this.dd.endDrag = this.endDrag.createDelegate(this);
-		this.dd.startDrag = this.startDrag.createDelegate(this);
-		this.dd.onDrag = this.onDrag.createDelegate(this);
-	},
-
-	onMouseOver: function(){
-		if (this.disabled) {
-			return;
-		}
-		var middle = this.getMiddle();
-		this.tmpHoverClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-overup' : 'x-form-spinner-overdown';
-		this.trigger.addClass(this.tmpHoverClass);
-	},
-
-	//private
-	onMouseOut: function(){
-		this.trigger.removeClass(this.tmpHoverClass);
-	},
-
-	//private
-	onMouseMove: function(){
-		if (this.disabled) {
-			return;
-		}
-		var middle = this.getMiddle();
-		if (((Ext.EventObject.getPageY() > middle) && this.tmpHoverClass == "x-form-spinner-overup") ||
-		((Ext.EventObject.getPageY() < middle) && this.tmpHoverClass == "x-form-spinner-overdown")) {
-		}
-	},
-
-	//private
-	onMouseDown: function(){
-		if (this.disabled) {
-			return;
-		}
-		var middle = this.getMiddle();
-		this.tmpClickClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-clickup' : 'x-form-spinner-clickdown';
-		this.trigger.addClass(this.tmpClickClass);
-	},
-
-	//private
-	onMouseUp: function(){
-		this.trigger.removeClass(this.tmpClickClass);
-	},
-
-	//private
-	onTriggerClick: function(){
-		if (this.disabled || this.el.dom.readOnly) {
-			return;
-		}
-		var middle = this.getMiddle();
-		var ud = (Ext.EventObject.getPageY() < middle) ? 'Up' : 'Down';
-		this['onSpin' + ud]();
-	},
-
-	//private
-	getMiddle: function(){
-		var t = this.trigger.getTop();
-		var h = this.trigger.getHeight();
-		var middle = t + (h / 2);
-		return middle;
-	},
-
-	//private
-	//checks if control is allowed to spin
-	isSpinnable: function(){
-		if (this.disabled || this.el.dom.readOnly) {
-			Ext.EventObject.preventDefault(); //prevent scrolling when disabled/readonly
-			return false;
-		}
-		return true;
-	},
-
-	handleMouseWheel: function(e){
-		//disable scrolling when not focused
-		if (this.wrap.hasClass('x-trigger-wrap-focus') == false) {
-			return;
-		}
-
-		var delta = e.getWheelDelta();
-		if (delta > 0) {
-			this.onSpinUp();
-			e.stopEvent();
-		} else {
-			if (delta < 0) {
-				this.onSpinDown();
-				e.stopEvent();
-			}
-		}
-	},
-
-	//private
-	startDrag: function(){
-		this.proxy.show();
-		this._previousY = Ext.fly(this.dd.getDragEl()).getTop();
-	},
-
-	//private
-	endDrag: function(){
-		this.proxy.hide();
-	},
-
-	//private
-	onDrag: function(){
-		if (this.disabled) {
-			return;
-		}
-		var y = Ext.fly(this.dd.getDragEl()).getTop();
-		var ud = '';
-
-		if (this._previousY > y) {
-			ud = 'Up';
-		} //up
-		if (this._previousY < y) {
-			ud = 'Down';
-		} //down
-		if (ud != '') {
-			this['onSpin' + ud]();
-		}
-
-		this._previousY = y;
-	},
-
-	//private
-	onSpinUp: function(){
-		if (this.isSpinnable() == false) {
-			return;
-		}
-		if (Ext.EventObject.shiftKey == true) {
-			this.onSpinUpAlternate();
-			return;
-		}
-		else {
-			this.spin(false, false);
-		}
-		this.field.fireEvent("spin", this.field);
-		this.field.fireEvent("spinup", this.field);
-	},
-
-	//private
-	onSpinDown: function(){
-		if (this.isSpinnable() == false) {
-			return;
-		}
-		if (Ext.EventObject.shiftKey == true) {
-			this.onSpinDownAlternate();
-			return;
-		}
-		else {
-			this.spin(true, false);
-		}
-		this.field.fireEvent("spin", this.field);
-		this.field.fireEvent("spindown", this.field);
-	},
-
-	//private
-	onSpinUpAlternate: function(){
-		if (this.isSpinnable() == false) {
-			return;
-		}
-		this.spin(false, true);
-		this.field.fireEvent("spin", this);
-		this.field.fireEvent("spinup", this);
-	},
-
-	//private
-	onSpinDownAlternate: function(){
-		if (this.isSpinnable() == false) {
-			return;
-		}
-		this.spin(true, true);
-		this.field.fireEvent("spin", this);
-		this.field.fireEvent("spindown", this);
-	},
-
-	spin: function(down, alternate){
-		var v = parseFloat(this.field.getValue());
-		var incr = (alternate == true) ? this.alternateIncrementValue : this.incrementValue;
-		(down == true) ? v -= incr : v += incr;
-
-		v = (isNaN(v)) ? this.defaultValue : v;
-		v = this.fixBoundaries(v);
-		this.field.setRawValue(v);
-	},
-
-	fixBoundaries: function(value){
-		var v = value;
-
-		if (this.field.minValue != undefined && v < this.field.minValue) {
-			v = this.field.minValue;
-		}
-		if (this.field.maxValue != undefined && v > this.field.maxValue) {
-			v = this.field.maxValue;
-		}
-
-		return this.fixPrecision(v);
-	},
-
-	// private
-	fixPrecision: function(value){
-		var nan = isNaN(value);
-		if (!this.field.allowDecimals || this.field.decimalPrecision == -1 || nan || !value) {
-			return nan ? '' : value;
-		}
-		return parseFloat(parseFloat(value).toFixed(this.field.decimalPrecision));
-	},
-
-	doDestroy: function(){
-		if (this.trigger) {
-			this.trigger.remove();
-		}
-		if (this.wrap) {
-			this.wrap.remove();
-			delete this.field.wrap;
-		}
-
-		if (this.splitter) {
-			this.splitter.remove();
-		}
-
-		if (this.dd) {
-			this.dd.unreg();
-			this.dd = null;
-		}
-
-		if (this.proxy) {
-			this.proxy.remove();
-		}
-
-		if (this.repeater) {
-			this.repeater.purgeListeners();
-		}
-		if (this.mimicing){
-			Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this);
-		}
-	}
-});
-
-//backwards compat
-Ext.form.Spinner = Ext.ux.Spinner;
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport.js
deleted file mode 100644
index e982b3bafa76bd59801746b560403ddc7915f081..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport.js
+++ /dev/null
@@ -1,275 +0,0 @@
-Ext.namespace('TYPO3.Form', 'TYPO3.Form.Wizard');
-
-/**
- * The viewport
- *
- * @class TYPO3.Form.Wizard.Viewport
- * @extends Ext.Container
- */
-TYPO3.Form.Wizard.Viewport = Ext.extend(Ext.Container, {
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'formwizard',
-
-	/**
-	 * @cfg {Boolean} border
-	 * True to display the borders of the panel's body element, false to hide
-	 * them (defaults to true). By default, the border is a 2px wide inset
-	 * border, but this can be further altered by setting bodyBorder to false.
-	 */
-	border: false,
-
-	/**
-	 * @cfg {Mixed} renderTo
-	 * Specify the id of the element, a DOM element or an existing Element that
-	 * this component will be rendered into.
-	 */
-	renderTo: 'typo3-inner-docbody',
-
-	/**
-	 * @cfg {String} layout
-	 * In order for child items to be correctly sized and positioned, typically
-	 * a layout manager must be specified through the layout configuration option.
-	 *
-	 * The sizing and positioning of child items is the responsibility of the
-	 * Container's layout manager which creates and manages the type of layout
-	 * you have in mind.
-	 */
-	layout: 'border',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the left and right part to the viewport
-	 * Add the history buttons
-	 * @todo Move the buttons to the docheader
-	 */
-	initComponent: function() {
-		var config = {
-			items: [
-				{
-					xtype: 'typo3-form-wizard-viewport-left'
-				},{
-					xtype: 'typo3-form-wizard-viewport-right'
-				}
-			]
-		};
-
-			// Add the buttons to the docheader
-		this.splitButtons.addPreSubmitCallback(this.save);
-		this.hijackTBE();
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.superclass.initComponent.apply(this, arguments);
-	},
-
-	/**
-	 * hijack TBE save method
-	 */
-	hijackTBE: function() {
-		/**
-		 * @see TBE_EDITOR.submitForm
-		 */
-		TBE_EDITOR.submitForm = function() {
-			if (TBE_EDITOR.doSaveFieldName) {
-				document[TBE_EDITOR.formname][TBE_EDITOR.doSaveFieldName].value=1;
-			}
-			// Set a short timeout to allow other JS processes to complete, in particular those from
-			// EXT:backend/Resources/Public/JavaScript/FormEngine.js (reference: http://forge.typo3.org/issues/58755).
-			// TODO: This should be solved in a better way when this script is refactored.
-			window.setTimeout(function() {
-				var form0 = document.getElementsByName(TBE_EDITOR.formname).item(0);
-				if(form0 && form0.dataset.typo3_formwizard == 'wait') {
-					TBE_EDITOR.submitForm();
-					return;
-				}
-				document.getElementsByName(TBE_EDITOR.formname).item(0).submit();
-			}, 10);
-		}
-	},
-
-	/**
-	 * Add the buttons to the docheader
-	 *
-	 * All buttons except close will be handled by the form wizard javascript
-	 * The save and history buttons are put into separate buttongroups, click
-	 * event listeners are added.
-	 */
-	addButtonsToDocHeader: function() {
-		var docHeaderRow1 = Ext.get('typo3-docheader');
-		var docHeaderButtonsBar = docHeaderRow1.first('.typo3-docheader-buttons');
-		var docHeaderRow1ButtonsLeft = docHeaderButtonsBar.first('.left');
-
-		var saveButtonGroup = Ext.DomHelper.append(docHeaderRow1ButtonsLeft, {
-			tag: 'div',
-			cls: 'buttongroup'
-		});
-
-		var save = new Ext.Element(
-			Ext.DomHelper.append(saveButtonGroup, {
-				tag: 'span',
-				cls: 't3-icon t3-icon-actions t3-icon-actions-document t3-icon-document-save',
-				id: 'formwizard-save',
-				title: TYPO3.l10n.localize('save')
-			})
-		);
-
-		var saveAndClose = new Ext.Element(
-				Ext.DomHelper.append(saveButtonGroup, {
-					tag: 'span',
-					cls: 't3-icon t3-icon-actions t3-icon-actions-document t3-icon-document-save-close',
-					id: 'formwizard-saveandclose',
-					title: TYPO3.l10n.localize('saveAndClose')
-				})
-			);
-
-		save.on('click', this.save, this);
-		saveAndClose.on('click', this.saveAndClose, this);
-
-		var historyButtonGroup = Ext.DomHelper.append(docHeaderRow1ButtonsLeft, {
-			tag: 'div',
-			cls: 'buttongroup'
-		});
-
-		var undo = new Ext.Element(
-			Ext.DomHelper.append(historyButtonGroup, {
-				tag: 'span',
-				cls: 't3-icon t3-icon-actions t3-icon-actions-document t3-icon-view-go-back',
-				id: 'formwizard-history-undo',
-				title: TYPO3.l10n.localize('history_undo')
-			})
-		);
-
-		var redo = new Ext.Element(
-			Ext.DomHelper.append(historyButtonGroup, {
-				tag: 'span',
-				cls: 't3-icon t3-icon-actions t3-icon-actions-document t3-icon-view-go-forward',
-				id: 'formwizard-history-redo',
-				title: TYPO3.l10n.localize('history_redo')
-			})
-		);
-
-		undo.hide();
-		undo.on('click', this.undo, this);
-
-		redo.hide();
-		redo.on('click', this.redo, this);
-	},
-
-	/**
-	 * @returns {Element}
-	 */
-	getEditForm: function() {
-		return document.querySelector('[name=editform]');
-	},
-
-	/**
-	 * Save the form
-	 *
-	 * @param event
-	 * @param element
-	 * @param object
-	 */
-	save: function(event, element, object) {
-		var configuration = Ext.getCmp('formwizard-right').getConfiguration();
-		var wizardUrl = TYPO3.Form.Wizard.Settings.ajaxUrl;
-		var url = wizardUrl.substring(wizardUrl.indexOf('&P'));
-		url = TYPO3.settings.ajaxUrls['formwizard_save'] + url;
-
-		// prepare config json
-		var encodedConfiguration = Ext.encode(configuration);
-		var formData = new FormData();
-		formData.append('configuration', encodedConfiguration);
-		formData.append('action', 'save');
-
-		// get domElement
-		var Viewport = Ext.getCmp('formwizard');
-
-		// synchronous ajax request
-		var r = new XMLHttpRequest();
-		r.open("POST", url, true);
-		r.onreadystatechange = function () {
-			if (this.readyState != 4 || this.status != 200) return;
-			// form ready
-			var editForm = Viewport.getEditForm();
-			if(editForm) {
-				editform.dataset.typo3_formwizard = 'ready';
-			}
-			var responseObject = Ext.decode(this.responseText);
-			Viewport.transportEl.value = responseObject.fakeTs;
-		};
-		// form not ready
-		var editForm = Viewport.getEditForm();
-		if(editForm) {
-			editform.dataset.typo3_formwizard = 'wait';
-		}
-		r.send(formData);
-	},
-
-	/**
-	 * Save the form and close the wizard
-	 *
-	 * @param event
-	 * @param element
-	 * @param object
-	 */
-	saveAndClose: function(event, element, object) {
-		var configuration = Ext.getCmp('formwizard-right').getConfiguration();
-		var url = document.location.href.substring(document.location.href.indexOf('&P'));
-		url = TYPO3.settings.ajaxUrls['formwizard_save'] + url;
-		Ext.Ajax.request({
-			url: url,
-			method: 'POST',
-			params: {
-				configuration: Ext.encode(configuration)
-			},
-			success: function(response, opts) {
-				var urlParameters = Ext.urlDecode(document.location.search.substring(1));
-				document.location = urlParameters['P[returnUrl]'];
-			},
-			failure: function(response, opts) {
-				Ext.MessageBox.alert(
-					TYPO3.l10n.localize('action_save'),
-					TYPO3.l10n.localize('action_save_error') + ' ' + response.status
-				);
-			},
-			scope: this
-		});
-	},
-
-	/**
-	 * Get the previous snapshot from the history if available
-	 *
-	 * @param event
-	 * @param element
-	 * @param object
-	 */
-	undo: function(event, element, object) {
-		TYPO3.Form.Wizard.Helpers.History.undo();
-	},
-
-	/**
-	 * Get the next snapshot from the history if available
-	 *
-	 * @param event
-	 * @param element
-	 * @param object
-	 */
-	redo: function(event, element, object) {
-		TYPO3.Form.Wizard.Helpers.History.redo();
-	}
-});
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left.js
deleted file mode 100644
index 586d7defb1f0223e1d8b33e56d5829c63da26801..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left.js
+++ /dev/null
@@ -1,129 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport');
-
-/**
- * The tabpanel on the left side
- *
- * @class TYPO3.Form.Wizard.Viewport.Left
- * @extends Ext.TabPanel
- */
-TYPO3.Form.Wizard.Viewport.Left = Ext.extend(Ext.TabPanel, {
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'formwizard-left',
-
-	/**
-	 * @cfg {Integer} width
-	 * The width of this component in pixels (defaults to auto).
-	 */
-	width: 350,
-
-	/**
-	 * @cfg {String/Number} activeTab A string id or the numeric index of the tab that should be initially
-	 * activated on render (defaults to undefined).
-	 */
-	activeTab: 0,
-
-	/**
-	 * @cfg {String} region
-	 * Note: this config is only used when this BoxComponent is rendered
-	 * by a Container which has been configured to use the BorderLayout
-	 * layout manager (e.g. specifying layout:'border').
-	 */
-	region: 'west',
-
-	/**
-	 * @cfg {Boolean} autoScroll
-	 * true to use overflow:'auto' on the components layout element and show
-	 * scroll bars automatically when necessary, false to clip any overflowing
-	 * content (defaults to false).
-	 */
-	autoScroll: true,
-
-	/**
-	 * @cfg {Boolean} border
-	 * True to display the borders of the panel's body element, false to hide
-	 * them (defaults to true). By default, the border is a 2px wide inset border,
-	 * but this can be further altered by setting {@link #bodyBorder} to false.
-	 */
-	border: false,
-
-	/**
-	 * @cfg {Object|Function} defaults
-	 *
-	 * This option is a means of applying default settings to all added items
-	 * whether added through the items config or via the add or insert methods.
-	 */
-	defaults: {
-		autoHeight: true,
-		autoWidth: true
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the tabs to the tabpanel
-	 */
-	initComponent: function() {
-		var allowedTabs = TYPO3.Form.Wizard.Settings.defaults.showTabs.split(/[, ]+/);
-		var tabs = [];
-
-		Ext.each(allowedTabs, function(option, index, length) {
-			var tabXtype = 'typo3-form-wizard-viewport-left-' + option;
-			if (Ext.ComponentMgr.isRegistered(tabXtype)) {
-				tabs.push({
-					xtype: tabXtype
-				});
-			}
-		}, this);
-
-		var config = {
-			items: tabs
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.superclass.initComponent.apply(this, arguments);
-
-			// Set the focus when a tab has changed. We need this to remove focus from forms
-		this.on('tabchange', this.setFocus, this);
-	},
-
-	/**
-	 * Set the focus to a tab
-	 *
-	 * doLayout is necessary, because the tabs are sometimes emptied and filled
-	 * again, for instance by the history. Otherwise after a history undo or redo
-	 * the options and form tabs are empty.
-	 *
-	 * @param tabPanel
-	 * @param tab
-	 */
-	setFocus: function(tabPanel, tab) {
-		tabPanel.doLayout();
-		tab.el.focus();
-	},
-
-	/**
-	 * Set the options tab as active tab
-	 *
-	 * Called by the options panel when an element has been selected
-	 */
-	setOptionsTab: function() {
-		this.setActiveTab('formwizard-left-options');
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left', TYPO3.Form.Wizard.Viewport.Left);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements.js
deleted file mode 100644
index 72a06a0d7fb3f664acb51174b2f20e79eae1ad83..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements.js
+++ /dev/null
@@ -1,96 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left');
-
-/**
- * The elements panel in the elements tab on the left side
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Elements
- * @extends Ext.Panel
- */
-TYPO3.Form.Wizard.Viewport.Left.Elements = Ext.extend(Ext.Panel, {
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'formwizard-left-elements',
-
-	/**
-	 * @cfg {String} cls
-	 * An optional extra CSS class that will be added to this component's
-	 * Element (defaults to ''). This can be useful for adding customized styles
-	 * to the component or any of its children using standard CSS rules.
-	 */
-	cls: 'x-tab-panel-body-content',
-
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('left_elements'),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the form elements to the tab
-	 */
-	initComponent: function() {
-		var allowedAccordions = TYPO3.Form.Wizard.Settings.defaults.tabs.elements.showAccordions.split(/[, ]+/);
-		var accordions = [];
-
-		Ext.each(allowedAccordions, function(option, index, length) {
-			var accordionXtype = 'typo3-form-wizard-viewport-left-elements-' + option;
-			if (Ext.ComponentMgr.isRegistered(accordionXtype)) {
-				accordions.push({
-					xtype: accordionXtype
-				});
-			}
-		}, this);
-
-		var config = {
-			items: [
-				{
-					xtype: 'container',
-					id: 'formwizard-left-elements-intro',
-					tpl: new Ext.XTemplate(
-						'<tpl for=".">',
-							'<p><strong>{title}</strong></p>',
-							'<p>{description}</p>',
-						'</tpl>'
-					),
-					data: [{
-						title: TYPO3.l10n.localize('left_elements_intro_title'),
-						description: TYPO3.l10n.localize('left_elements_intro_description')
-					}],
-					cls: 'formwizard-left-dummy typo3-message message-information'
-				}, {
-					xtype: 'panel',
-					layout: 'accordion',
-					border: false,
-					padding: 0,
-					defaults: {
-						autoHeight: true,
-						cls: 'x-panel-accordion'
-					},
-					items: accordions
-				}
-			]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Elements.superclass.initComponent.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-elements', TYPO3.Form.Wizard.Viewport.Left.Elements);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements/Basic.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements/Basic.js
deleted file mode 100644
index 4f2e0fdc0f8da199f7b29f07750836e4681e4ba2..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements/Basic.js
+++ /dev/null
@@ -1,178 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Elements');
-
-/**
- * The basic elements in the elements tab on the left side
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Elements.Basic
- * @extends TYPO3.Form.Wizard.Viewport.Left.Elements.ButtonGroup
- */
-TYPO3.Form.Wizard.Viewport.Left.Elements.Basic = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Elements.ButtonGroup, {
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'formwizard-left-elements-basic',
-
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('left_elements_basic'),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the buttons to the accordion
-	 */
-	initComponent: function() {
-		var allowedButtons = TYPO3.Form.Wizard.Settings.defaults.tabs.elements.accordions.basic.showButtons.split(/[, ]+/);
-		var buttons = [];
-
-		Ext.each(allowedButtons, function(option, index, length) {
-			switch (option) {
-				case 'button':
-					buttons.push({
-						text: TYPO3.l10n.localize('basic_button'),
-						id: 'basic-button',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-basic-button',
-						scope: this
-					});
-					break;
-				case 'checkbox':
-					buttons.push({
-						text: TYPO3.l10n.localize('basic_checkbox'),
-						id: 'basic-checkbox',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-basic-checkbox',
-						scope: this
-					});
-					break;
-				case 'fieldset':
-					buttons.push({
-						text: TYPO3.l10n.localize('basic_fieldset'),
-						id: 'basic-fieldset',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-basic-fieldset',
-						scope: this
-					});
-					break;
-				case 'fileupload':
-					buttons.push({
-						text: TYPO3.l10n.localize('basic_fileupload'),
-						id: 'basic-fileupload',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-basic-fileupload',
-						scope: this
-					});
-					break;
-				case 'hidden':
-					buttons.push({
-						text: TYPO3.l10n.localize('basic_hidden'),
-						id: 'basic-hidden',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-basic-hidden',
-						scope: this
-					});
-					break;
-				case 'password':
-					buttons.push({
-						text: TYPO3.l10n.localize('basic_password'),
-						id: 'basic-password',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-basic-password',
-						scope: this
-					});
-					break;
-				case 'radio':
-					buttons.push({
-						text: TYPO3.l10n.localize('basic_radio'),
-						id: 'basic-radio',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-basic-radio',
-						scope: this
-					});
-					break;
-				case 'reset':
-					buttons.push({
-						text: TYPO3.l10n.localize('basic_reset'),
-						id: 'basic-reset',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-basic-reset',
-						scope: this
-					});
-					break;
-				case 'select':
-					buttons.push({
-						text: TYPO3.l10n.localize('basic_select'),
-						id: 'basic-select',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-basic-select',
-						scope: this
-					});
-					break;
-				case 'submit':
-					buttons.push({
-						text: TYPO3.l10n.localize('basic_submit'),
-						id: 'basic-submit',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-basic-submit',
-						scope: this
-					});
-					break;
-				case 'textarea':
-					buttons.push({
-						text: TYPO3.l10n.localize('basic_textarea'),
-						id: 'basic-textarea',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-basic-textarea',
-						scope: this
-					});
-					break;
-				case 'textline':
-					buttons.push({
-						text: TYPO3.l10n.localize('basic_textline'),
-						id: 'basic-textline',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-basic-textline',
-						scope: this
-					});
-					break;
-			}
-		}, this);
-
-		var config = {
-			items: buttons
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Elements.Basic.superclass.initComponent.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-elements-basic', TYPO3.Form.Wizard.Viewport.Left.Elements.Basic);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements/ButtonGroup.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements/ButtonGroup.js
deleted file mode 100644
index d7d91ed227f0b8820ef34e0fec9950904c09ce47..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements/ButtonGroup.js
+++ /dev/null
@@ -1,122 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Elements');
-
-/**
- * The button group abstract for the elements tab on the left side
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Elements.ButtonGroup
- * @extends Ext.ButtonGroup
- */
-TYPO3.Form.Wizard.Viewport.Left.Elements.ButtonGroup = Ext.extend(Ext.Panel, {
-	/**
-	 * @cfg {Object|Function} defaults
-	 * This option is a means of applying default settings to all added items
-	 * whether added through the items config or via the add or insert methods.
-	 */
-	defaults: {
-		xtype: 'button',
-		scale: 'small',
-		width: 140,
-		iconAlign: 'left',
-		cls: 'formwizard-element'
-	},
-
-	cls: 'formwizard-buttongroup',
-
-	/**
-	 * @cfg {Boolean} autoHeight
-	 * true to use height:'auto', false to use fixed height (defaults to false).
-	 * Note: Setting autoHeight: true means that the browser will manage the panel's height
-	 * based on its contents, and that Ext will not manage it at all. If the panel is within a layout that
-	 * manages dimensions (fit, border, etc.) then setting autoHeight: true
-	 * can cause issues with scrolling and will not generally work as expected since the panel will take
-	 * on the height of its contents rather than the height required by the Ext layout.
-	 */
-	autoHeight: true,
-
-	/**
-	 * @cfg {Number/String} padding
-	 * A shortcut for setting a padding style on the body element. The value can
-	 * either be a number to be applied to all sides, or a normal css string
-	 * describing padding.
-	 */
-	padding: 0,
-
-	/**
-	 * @cfg {String} layout
-	 * In order for child items to be correctly sized and positioned, typically
-	 * a layout manager must be specified through the layout configuration option.
-	 *
-	 * The sizing and positioning of child items is the responsibility of the
-	 * Container's layout manager which creates and manages the type of layout
-	 * you have in mind.
-	 */
-	layout: 'table',
-
-	/**
-	 * @cfg {Object} layoutConfig
-	 * This is a config object containing properties specific to the chosen
-	 * layout if layout has been specified as a string.
-	 */
-	layoutConfig: {
-		columns: 2
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the buttons to the accordion
-	 */
-	initComponent: function() {
-		var config = {};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Elements.ButtonGroup.superclass.initComponent.apply(this, arguments);
-
-			// Initialize the dragzone after rendering
-		this.on('render', this.initializeDrag, this);
-	},
-
-	/**
-	 * Initialize the drag zone.
-	 *
-	 * @param buttonGroup
-	 */
-	initializeDrag: function(buttonGroup) {
-		buttonGroup.dragZone = new Ext.dd.DragZone(buttonGroup.getEl(), {
-			getDragData: function(element) {
-				var sourceElement = element.getTarget('.formwizard-element');
-				if (sourceElement) {
-					clonedElement = sourceElement.cloneNode(true);
-					clonedElement.id = Ext.id();
-					return buttonGroup.dragData = {
-						sourceEl: sourceElement,
-						repairXY: Ext.fly(sourceElement).getXY(),
-						ddel: clonedElement
-					};
-				}
-			},
-			getRepairXY: function() {
-				return buttonGroup.dragData.repairXY;
-			}
-		});
-	},
-
-	/**
-	 * Called when a button has been double clicked
-	 *
-	 * Tells the form in the right container to add a new element, according to
-	 * the button which has been clicked.
-	 *
-	 * @param button
-	 * @param event
-	 */
-	onDoubleClick: function(button, event) {
-		var formContainer = Ext.getCmp('formwizard-right').get(0).containerComponent;
-		formContainer.dropElement(button, 'container');
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-elements-buttongroup', TYPO3.Form.Wizard.Viewport.Left.Elements.ButtonGroup);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements/Content.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements/Content.js
deleted file mode 100644
index bfcb0c3f9da7b6e369d2c9f6e42ccb3c0ed449f1..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements/Content.js
+++ /dev/null
@@ -1,78 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Elements');
-
-/**
- * The content elements in the elements tab on the left side
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Elements.Content
- * @extends TYPO3.Form.Wizard.Viewport.Left.Elements.ButtonGroup
- */
-TYPO3.Form.Wizard.Viewport.Left.Elements.Content = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Elements.ButtonGroup, {
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'formwizard-left-elements-content',
-
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('left_elements_content'),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the buttons to the accordion
-	 */
-	initComponent: function() {
-		var allowedButtons = TYPO3.Form.Wizard.Settings.defaults.tabs.elements.accordions.content.showButtons.split(/[, ]+/);
-		var buttons = [];
-
-		Ext.each(allowedButtons, function(option, index, length) {
-			switch (option) {
-				case 'header':
-					buttons.push({
-						text: TYPO3.l10n.localize('content_header'),
-						id: 'content-header',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-content-header',
-						scope: this
-					});
-					break;
-				case 'textblock':
-					buttons.push({
-						text: TYPO3.l10n.localize('content_textblock'),
-						id: 'content-textblock',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-content-textblock',
-						scope: this
-					});
-					break;
-			}
-		}, this);
-
-		var config = {
-			items: buttons
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Elements.Content.superclass.initComponent.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-elements-content', TYPO3.Form.Wizard.Viewport.Left.Elements.Content);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements/Predefined.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements/Predefined.js
deleted file mode 100644
index d1596e90e3bc66aecbc3245f523553ff067c17a8..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Elements/Predefined.js
+++ /dev/null
@@ -1,98 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Elements');
-
-/**
- * The predefined elements in the elements tab on the left side
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Elements.Predefined
- * @extends TYPO3.Form.Wizard.Viewport.Left.Elements.ButtonGroup
- */
-TYPO3.Form.Wizard.Viewport.Left.Elements.Predefined = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Elements.ButtonGroup, {
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'formwizard-left-elements-predefined',
-
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('left_elements_predefined'),
-
-	/**
-	 * Constructor
-	 *
-	 * Add the buttons to the accordion
-	 */
-	initComponent: function() {
-		var allowedButtons = TYPO3.Form.Wizard.Settings.defaults.tabs.elements.accordions.predefined.showButtons.split(/[, ]+/);
-		var buttons = [];
-
-		Ext.each(allowedButtons, function(option, index, length) {
-			switch (option) {
-				case 'email':
-					buttons.push({
-						text: TYPO3.l10n.localize('predefined_email'),
-						id: 'predefined-email',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-predefined-email',
-						scope: this
-					});
-					break;
-				case 'radiogroup':
-					buttons.push({
-						text: TYPO3.l10n.localize('predefined_radiogroup'),
-						id: 'predefined-radiogroup',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-predefined-radiogroup',
-						scope: this
-					});
-					break;
-				case 'checkboxgroup':
-					buttons.push({
-						text: TYPO3.l10n.localize('predefined_checkboxgroup'),
-						id: 'predefined-checkboxgroup',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-predefined-checkboxgroup',
-						scope: this
-					});
-					break;
-				case 'name':
-					buttons.push({
-						text: TYPO3.l10n.localize('predefined_name'),
-						id: 'predefined-name',
-						clickEvent: 'dblclick',
-						handler: this.onDoubleClick,
-						iconCls: 'formwizard-left-elements-predefined-name',
-						scope: this
-					});
-					break;
-			}
-		}, this);
-
-		var config = {
-			items: buttons
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Elements.Predefined.superclass.initComponent.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-elements-predefined', TYPO3.Form.Wizard.Viewport.Left.Elements.Predefined);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form.js
deleted file mode 100644
index 89264b98544761f75a9451be85ed31f12bac0ceb..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form.js
+++ /dev/null
@@ -1,194 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.LeftTYPO3.Form.Wizard.Elements');
-
-/**
- * The form tab on the left side
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Form
- * @extends Ext.Panel
- */
-TYPO3.Form.Wizard.Viewport.Left.Form = Ext.extend(Ext.Panel, {
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'formwizard-left-form',
-
-	/**
-	 * @cfg {String} cls
-	 * An optional extra CSS class that will be added to this component's
-	 * Element (defaults to ''). This can be useful for adding customized styles
-	 * to the component or any of its children using standard CSS rules.
-	 */
-	cls: 'x-tab-panel-body-content',
-
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('left_form'),
-
-	/**
-	 * @cfg {Boolean} border
-	 * True to display the borders of the panel's body element, false to hide
-	 * them (defaults to true). By default, the border is a 2px wide inset
-	 * border, but this can be further altered by setting bodyBorder to false.
-	 */
-	border: false,
-
-	/**
-	 * @cfg {Object|Function} defaults
-	 * This option is a means of applying default settings to all added items
-	 * whether added through the items config or via the add or insert methods.
-	 */
-	defaults: {
-		//autoHeight: true,
-		border: false,
-		padding: 0
-	},
-
-	/**
-	 * @cfg {Object} validAccordions
-	 * Keeps track which accordions are valid. Accordions contain forms which
-	 * do client validation. If there is a validation change in a form in the
-	 * accordion, a validation event will be fired, which changes one of these
-	 * values
-	 */
-	validAccordions: {
-		behaviour: true,
-		prefix: true,
-		attributes: true,
-		postProcessor: true
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the form elements to the tab
-	 */
-	initComponent: function() {
-		var config = {
-			items: [{
-				xtype: 'panel',
-				layout: 'accordion',
-				ref: 'accordion',
-				defaults: {
-					autoHeight: true,
-					cls: 'x-panel-accordion'
-				}
-			}]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Form.superclass.initComponent.apply(this, arguments);
-	},
-
-	/**
-	 * Called whenever a form has been added to the right container
-	 *
-	 * Sets element to the form component and calls the function to add the
-	 * attribute fields
-	 *
-	 * @param form
-	 */
-	setForm: function(form) {
-		var allowedAccordions = TYPO3.Form.Wizard.Settings.defaults.tabs.form.showAccordions.split(/[, ]+/);
-
-		this.accordion.removeAll();
-		if (form) {
-			Ext.each(allowedAccordions, function(option, index, length) {
-				switch (option) {
-					case 'behaviour':
-						this.accordion.add({
-							xtype: 'typo3-form-wizard-viewport-left-form-behaviour',
-							element: form,
-							listeners: {
-								'validation': {
-									fn: this.validation,
-									scope: this
-								}
-							}
-						});
-						break;
-					case 'prefix':
-						this.accordion.add({
-							xtype: 'typo3-form-wizard-viewport-left-form-prefix',
-							element: form,
-							listeners: {
-								'validation': {
-									fn: this.validation,
-									scope: this
-								}
-							}
-						});
-						break;
-					case 'attributes':
-						this.accordion.add({
-							xtype: 'typo3-form-wizard-viewport-left-form-attributes',
-							element: form,
-							listeners: {
-								'validation': {
-									fn: this.validation,
-									scope: this
-								}
-							}
-						});
-						break;
-					case 'postProcessor':
-						this.accordion.add({
-							xtype: 'typo3-form-wizard-viewport-left-form-postprocessor',
-							element: form,
-							listeners: {
-								'validation': {
-									fn: this.validation,
-									scope: this
-								}
-							}
-						});
-						break;
-				}
-			}, this);
-		}
-		this.doLayout();
-	},
-
-	/**
-	 * Called by the validation listeners of the accordions
-	 *
-	 * Checks if all accordions are valid. If not, adds a class to the tab
-	 *
-	 * @param {String} accordion The accordion which fires the event
-	 * @param {Boolean} isValid Accordion is valid or not
-	 */
-	validation: function(accordion, isValid) {
-		this.validAccordions[accordion] = isValid;
-		var tabIsValid = true;
-		Ext.iterate(this.validAccordions, function(key, value) {
-			if (!value) {
-				tabIsValid = false;
-			}
-		}, this);
-		if (this.tabEl) {
-			var tabEl = Ext.get(this.tabEl);
-			if (tabIsValid && tabEl.hasClass('validation-error')) {
-				tabEl.removeClass('validation-error');
-			} else if (!tabIsValid && !tabEl.hasClass('validation-error')) {
-				tabEl.addClass('validation-error');
-			}
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-form', TYPO3.Form.Wizard.Viewport.Left.Form);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/Attributes.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/Attributes.js
deleted file mode 100644
index a98943f5110eff44f659857a1ab5d9d8e852987a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/Attributes.js
+++ /dev/null
@@ -1,26 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Form');
-
-/**
- * The attributes panel in the accordion of the form tab on the left side
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Form.Attributes
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Attributes
- */
-TYPO3.Form.Wizard.Viewport.Left.Form.Attributes = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Attributes, {
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'formwizard-left-form-attributes'
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-form-attributes', TYPO3.Form.Wizard.Viewport.Left.Form.Attributes);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/Behaviour.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/Behaviour.js
deleted file mode 100644
index f097e49376c15d3f800c315480afc29fc4b775fc..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/Behaviour.js
+++ /dev/null
@@ -1,128 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Form');
-
-/**
- * The behaviour panel in the accordion of the form tab on the left side
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Form.Behaviour
- * @extends Ext.Panel
- */
-TYPO3.Form.Wizard.Viewport.Left.Form.Behaviour = Ext.extend(Ext.ux.form.FakeFormPanel, {
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'formwizard-left-form-behaviour',
-
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('form_behaviour'),
-
-	/**
-	 * @cfg {String} defaultType
-	 *
-	 * The default xtype of child Components to create in this Container when
-	 * a child item is specified as a raw configuration object,
-	 * rather than as an instantiated Component.
-	 *
-	 * Defaults to 'panel', except Ext.menu.Menu which defaults to 'menuitem',
-	 * and Ext.Toolbar and Ext.ButtonGroup which default to 'button'.
-	 */
-	defaultType: 'textfield',
-
-	/**
-	 * @cfg {Object} element
-	 * The form component
-	 */
-	element: null,
-
-	/**
-	 * Constructor
-	 *
-	 * @param config
-	 */
-	constructor: function(config){
-		// Call our superclass constructor to complete construction process.
-		TYPO3.Form.Wizard.Viewport.Left.Form.Behaviour.superclass.constructor.call(this, config);
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the form elements to the tab
-	 */
-	initComponent: function() {
-		var config = {
-			items: [{
-				xtype: 'fieldset',
-				title: '',
-				ref: 'fieldset',
-				autoHeight: true,
-				border: false,
-				defaults: {
-					width: 150,
-					msgTarget: 'side'
-				},
-				defaultType: 'checkbox',
-				items: [
-					{
-						fieldLabel: TYPO3.l10n.localize('behaviour_confirmation_page'),
-						name: 'confirmation',
-						listeners: {
-							'check': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					}
-				]
-			}]
-		};
-
-		// Apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-		// Call parent
-		TYPO3.Form.Wizard.Viewport.Left.Form.Behaviour.superclass.initComponent.apply(this, arguments);
-
-		// Fill the form with the configuration values
-		this.fillForm();
-	},
-
-
-	/**
-	 * Store a changed value from the form in the element
-	 *
-	 * @param {Object} field The field which has changed
-	 */
-	storeValue: function(field) {
-		var fieldName = field.getName();
-
-		var formConfiguration = {};
-		formConfiguration[fieldName] = field.getValue();
-
-		this.element.setConfigurationValue(formConfiguration);
-	},
-
-	/**
-	 * Fill the form with the configuration of the element
-	 *
-	 * @return void
-	 */
-	fillForm: function() {
-		this.getForm().setValues(this.element.configuration);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-form-behaviour', TYPO3.Form.Wizard.Viewport.Left.Form.Behaviour);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessor.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessor.js
deleted file mode 100644
index 001bdf8d64296145334db8f7406a7e3044ba9907..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessor.js
+++ /dev/null
@@ -1,210 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Form');
-
-/**
- * The post processor accordion panel in the form options in the left tabpanel
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessor
- * @extends Ext.Panel
- */
-TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessor = Ext.extend(Ext.Panel, {
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('form_postprocessor'),
-
-	/**
-	 * @cfg {Object} validPostProcessors
-	 * Keeps track which post processors are valid. Post processors contain forms which
-	 * do client validation. If there is a validation change in a form in the
-	 * post processor, a validation event will be fired, which changes one of these
-	 * values
-	 */
-	validPostProcessors: {
-		mail: true
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the post processors to the accordion
-	 */
-	initComponent: function() {
-		var postProcessors = this.getPostProcessorsBySettings();
-
-			// Adds the specified events to the list of events which this Observable may fire.
-		this.addEvents({
-			'validation': true
-		});
-
-		var config = {
-			items: [{
-				xtype: 'typo3-form-wizard-viewport-left-form-postprocessors-dummy',
-				ref: 'dummy'
-			}],
-			tbar: [
-				{
-					xtype: 'combo',
-					hideLabel: true,
-					name: 'postprocessor',
-					ref: 'postprocessor',
-					mode: 'local',
-					triggerAction: 'all',
-					forceSelection: true,
-					editable: false,
-					hiddenName: 'postprocessor',
-					emptyText: TYPO3.l10n.localize('postprocessor_emptytext'),
-					width: 150,
-					displayField: 'label',
-					valueField: 'value',
-					store: new Ext.data.JsonStore({
-						fields: ['label', 'value'],
-						data: postProcessors
-					}),
-					listeners: {
-						'select': {
-							scope: this,
-							fn: this.addPostProcessor
-						}
-					}
-				}
-			]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessor.superclass.initComponent.apply(this, arguments);
-
-			// Initialize the post processors when they are available for this element
-		this.initPostProcessors();
-	},
-
-	/**
-	 * Called when constructing the post processor accordion
-	 *
-	 * Checks if the form already has post processors and loads these instead of the dummy
-	 */
-	initPostProcessors: function() {
-		var postProcessors = this.element.configuration.postProcessor;
-		if (!Ext.isEmptyObject(postProcessors)) {
-			this.remove(this.dummy);
-			Ext.iterate(postProcessors, function(key, value) {
-				var xtype = 'typo3-form-wizard-viewport-left-form-postprocessors-' + key;
-				if (Ext.ComponentMgr.isRegistered(xtype)) {
-					this.add({
-						xtype: xtype,
-						element: this.element,
-						configuration: value,
-						listeners: {
-							'validation': {
-								fn: this.validation,
-								scope: this
-							}
-						}
-					});
-				}
-			}, this);
-		}
-	},
-
-	/**
-	 * Add a post processor to the list
-	 *
-	 * @param comboBox
-	 * @param record
-	 * @param index
-	 */
-	addPostProcessor: function(comboBox, record, index) {
-		var postProcessor = comboBox.getValue();
-		var xtype = 'typo3-form-wizard-viewport-left-form-postprocessors-' + postProcessor;
-
-		if (!Ext.isEmpty(this.findByType(xtype))) {
-			Ext.MessageBox.alert(TYPO3.l10n.localize('postprocessor_alert_title'), TYPO3.l10n.localize('postprocessor_alert_description'));
-		} else {
-			this.remove(this.dummy);
-
-			this.add({
-				xtype: xtype,
-				element: this.element,
-				listeners: {
-					'validation': {
-						fn: this.validation,
-						scope: this
-					}
-				}
-			});
-			this.doLayout();
-		}
-	},
-
-	/**
-	 * Remove a post processor from the list
-	 *
-	 * Shows dummy when there is no post processor for the form
-	 *
-	 * @param component
-	 */
-	removePostProcessor: function(component) {
-		this.remove(component);
-		this.validation(component.processor, true);
-		if (this.items.length == 0) {
-			this.add({
-				xtype: 'typo3-form-wizard-viewport-left-form-postprocessors-dummy',
-				ref: 'dummy'
-			});
-		}
-		this.doLayout();
-	},
-
-	getPostProcessorsBySettings: function() {
-		var postProcessors = [];
-
-		var allowedPostProcessors = [];
-		try {
-			allowedPostProcessors = TYPO3.Form.Wizard.Settings.defaults.tabs.form.accordions.postProcessor.showPostProcessors.split(/[, ]+/);
-		} catch (error) {
-			// The object has not been found
-			allowedPostProcessors = [
-				'mail'
-			];
-		}
-
-		Ext.iterate(allowedPostProcessors, function(item, index, allItems) {
-			postProcessors.push({label: TYPO3.l10n.localize('postprocessor_' + item), value: item});
-		}, this);
-
-		return postProcessors;
-	},
-
-	/**
-	 * Called by the validation listeners of the post processors
-	 *
-	 * Checks if all post processors are valid. If not, adds a class to the accordion
-	 *
-	 * @param {String} postProcessor The post processor which fires the event
-	 * @param {Boolean} isValid Post processor is valid or not
-	 */
-	validation: function(postProcessor, isValid) {
-		this.validPostProcessors[postProcessor] = isValid;
-		var accordionIsValid = true;
-		Ext.iterate(this.validPostProcessors, function(key, value) {
-			if (!value) {
-				accordionIsValid = false;
-			}
-		}, this);
-		if (this.el) {
-			if (accordionIsValid && this.el.hasClass('validation-error')) {
-				this.removeClass('validation-error');
-				this.fireEvent('validation', 'postProcessor', accordionIsValid);
-			} else if (!accordionIsValid && !this.el.hasClass('validation-error')) {
-				this.addClass('validation-error');
-				this.fireEvent('validation', 'postProcessor', accordionIsValid);
-			}
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-form-postprocessor', TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessor);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessors/Dummy.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessors/Dummy.js
deleted file mode 100644
index e5e00b3426cee12b0555817d34bdfb8e313f9c87..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessors/Dummy.js
+++ /dev/null
@@ -1,52 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors');
-
-/**
- * The dummy item when no post processor is defined for the form
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.Dummy
- * @extends Ext.Panel
- */
-TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.Dummy = Ext.extend(Ext.Panel, {
-	/**
-	 * @cfg {Boolean} border
-	 * True to display the borders of the panel's body element, false to hide
-	 * them (defaults to true). By default, the border is a 2px wide inset
-	 * border, but this can be further altered by setting bodyBorder to false.
-	 */
-	border: false,
-
-	/**
-	 * @cfg {Number/String} padding
-	 * A shortcut for setting a padding style on the body element. The value can
-	 * either be a number to be applied to all sides, or a normal css string
-	 * describing padding.
-	 */
-	padding: 0,
-
-	cls: 'formwizard-left-dummy typo3-message message-information',
-
-	/**
-	 * @cfg {Mixed} data
-	 * The initial set of data to apply to the tpl to update the content area of
-	 * the Component.
-	 */
-	data: [{
-		title: TYPO3.l10n.localize('postprocessor_dummy_title'),
-		description: TYPO3.l10n.localize('postprocessor_dummy_description')
-	}],
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<tpl for=".">',
-			'<p><strong>{title}</strong></p>',
-			'<p>{description}</p>',
-		'</tpl>'
-	)
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-form-postprocessors-dummy', TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.Dummy);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessors/Mail.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessors/Mail.js
deleted file mode 100644
index 614b3089c00639af87d6153359df63b6dd1e3652..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessors/Mail.js
+++ /dev/null
@@ -1,34 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors');
-
-/**
- * The mail post processor
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.Mail
- * @extends TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.PostProcessor
- */
-TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.Mail = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.PostProcessor, {
-	/**
-	 * @cfg {String} processor
-	 *
-	 * The name of this processor
-	 */
-	processor: 'mail',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				recipientEmail: '',
-				senderEmail: ''
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.Mail.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-form-postprocessors-mail', TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.Mail);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessors/PostProcessor.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessors/PostProcessor.js
deleted file mode 100644
index 699b27a418f256fa878fb579232c424902bff2bb..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessors/PostProcessor.js
+++ /dev/null
@@ -1,297 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors');
-
-/**
- * The post processor abstract
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.PostProcessor
- * @extends Ext.FormPanel
- */
-TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.PostProcessor = Ext.extend(Ext.ux.form.FakeFormPanel, {
-	/**
-	 * @cfg {Boolean} border
-	 * True to display the borders of the panel's body element, false to hide
-	 * them (defaults to true). By default, the border is a 2px wide inset
-	 * border, but this can be further altered by setting bodyBorder to false.
-	 */
-	border: false,
-
-	/**
-	 * @cfg {Number/String} padding
-	 * A shortcut for setting a padding style on the body element. The value can
-	 * either be a number to be applied to all sides, or a normal css string
-	 * describing padding.
-	 */
-	padding: 0,
-
-	/**
-	 * @cfg {String} defaultType
-	 *
-	 * The default xtype of child Components to create in this Container when
-	 * a child item is specified as a raw configuration object,
-	 * rather than as an instantiated Component.
-	 *
-	 * Defaults to 'panel', except Ext.menu.Menu which defaults to 'menuitem',
-	 * and Ext.Toolbar and Ext.ButtonGroup which default to 'button'.
-	 */
-	defaultType: 'textfield',
-
-	/**
-	 * @cfg {String} processor
-	 *
-	 * The name of this processor
-	 */
-	processor: '',
-
-	/**
-	 * @cfg {Boolean} monitorValid If true, the form monitors its valid state client-side and
-	 * regularly fires the clientvalidation event passing that state.
-	 * When monitoring valid state, the FormPanel enables/disables any of its configured
-	 * buttons which have been configured with formBind: true depending
-	 * on whether the form is valid or not. Defaults to false
-	 */
-	monitorValid: true,
-
-	/**
-	 * Constructor
-	 */
-	initComponent: function() {
-		var fields = this.getFieldsBySettings();
-		var formItems = new Array();
-
-			// Adds the specified events to the list of events which this Observable may fire.
-		this.addEvents({
-			'validation': true
-		});
-
-		Ext.iterate(fields, function(item, index, allItems) {
-			switch(item) {
-				case 'recipientEmail':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('postprocessor_properties_recipientemail'),
-						name: 'recipientEmail',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'senderEmail':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('postprocessor_properties_senderemail'),
-						name: 'senderEmail',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'subject':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('postprocessor_properties_subject'),
-						name: 'subject',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'destination':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('postprocessor_properties_destination'),
-						name: 'destination',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-			}
-		}, this);
-
-		formItems.push({
-			xtype: 'button',
-			text: TYPO3.l10n.localize('button_remove'),
-			handler: this.removePostProcessor,
-			scope: this
-		});
-
-		var config = {
-			items: [
-				{
-					xtype: 'fieldset',
-					title: TYPO3.l10n.localize('postprocessor_' + this.processor),
-					autoHeight: true,
-					defaults: {
-						width: 128,
-						msgTarget: 'side'
-					},
-					defaultType: 'textfieldsubmit',
-					items: formItems
-				}
-			]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.PostProcessor.superclass.initComponent.apply(this, arguments);
-
-			// Initialize clientvalidation event
-		this.on('clientvalidation', this.validation, this);
-
-			// Strange, but we need to call doLayout() after render
-		this.on('afterrender', this.newOrExistingPostProcessor, this);
-	},
-
-	/**
-	 * Decide whether this is a new or an existing one
-	 *
-	 * If new, the default configuration has to be added to the processors
-	 * of the form, otherwise we can fill the form with the existing configuration
-	 */
-	newOrExistingPostProcessor: function() {
-		this.doLayout();
-			// Existing processor
-		if (this.element.configuration.postProcessor[this.processor]) {
-			this.fillForm();
-			// New processor
-		} else {
-			this.addProcessorToElement();
-		}
-	},
-
-	/**
-	 * Fill the form with the configuration of the element
-	 *
-	 * When filling, the events of all form elements should be suspended,
-	 * otherwise the values are written back to the element, for instance on a
-	 * check event on a checkbox.
-	 */
-	fillForm: function() {
-		this.suspendEventsBeforeFilling();
-		this.getForm().setValues(this.element.configuration.postProcessor[this.processor]);
-		this.resumeEventsAfterFilling();
-	},
-
-	/**
-	 * Suspend the events on all items within this component
-	 */
-	suspendEventsBeforeFilling: function() {
-		this.cascade(function(item) {
-			item.suspendEvents();
-		});
-	},
-
-	/**
-	 * Resume the events on all items within this component
-	 */
-	resumeEventsAfterFilling: function() {
-		this.cascade(function(item) {
-			item.resumeEvents();
-		});
-	},
-
-	/**
-	 * Add this processor to the element
-	 */
-	addProcessorToElement: function() {
-		var formConfiguration = {postProcessor: {}};
-		formConfiguration.postProcessor[this.processor] = this.configuration;
-
-		this.element.setConfigurationValue(formConfiguration);
-
-		this.fillForm();
-	},
-
-	/**
-	 * Store a changed value from the form in the element
-	 *
-	 * @param {Object} field The field which has changed
-	 */
-	storeValue: function(field) {
-		if (field.isValid()) {
-			var fieldName = field.getName();
-
-			var formConfiguration = {postProcessor: {}};
-			formConfiguration.postProcessor[this.processor] = {};
-			formConfiguration.postProcessor[this.processor][fieldName] = field.getValue();
-
-			this.element.setConfigurationValue(formConfiguration);
-		}
-	},
-
-	/**
-	 * Remove the processor
-	 *
-	 * Called when the remove button of this processor has been clicked
-	 */
-	removePostProcessor: function() {
-		this.ownerCt.removePostProcessor(this);
-		this.element.removePostProcessor(this.processor);
-	},
-
-	/**
-	 * Get the fields for the element
-	 *
-	 * Based on the TSconfig general allowed fields
-	 * and the TSconfig allowed fields for this type of element
-	 *
-	 * @returns object
-	 */
-	getFieldsBySettings: function() {
-		var fields = [];
-		var processorFields = this.configuration;
-
-		var allowedFields = [];
-		try {
-			allowedFields = TYPO3.Form.Wizard.Settings.defaults.tabs.form.accordions.postProcessor.postProcessors[this.processor].showProperties.split(/[, ]+/);
-		} catch (error) {
-			// The object has not been found or constructed wrong
-			allowedFields = [
-				'recipientEmail',
-				'senderEmail'
-			];
-		}
-
-		Ext.iterate(allowedFields, function(item, index, allItems) {
-			fields.push(item);
-		}, this);
-
-		return fields;
-	},
-
-	/**
-	 * Called by the clientvalidation event
-	 *
-	 * Adds or removes the error class if the form is valid or not
-	 *
-	 * @param {Object} formPanel This formpanel
-	 * @param {Boolean} valid True if the client validation is true
-	 */
-	validation: function(formPanel, valid) {
-		if (this.el) {
-			if (valid && this.el.hasClass('validation-error')) {
-				this.removeClass('validation-error');
-				this.fireEvent('validation', this.processor, valid);
-			} else if (!valid && !this.el.hasClass('validation-error')) {
-				this.addClass('validation-error');
-				this.fireEvent('validation', this.processor, valid);
-			}
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-form-postprocessors-postprocessor', TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.PostProcessor);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessors/Redirect.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessors/Redirect.js
deleted file mode 100644
index 5ef78ddc45e08898aeb849c6253ed94c0ede0146..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/PostProcessors/Redirect.js
+++ /dev/null
@@ -1,33 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors');
-
-/**
- * The redirect post processor
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.Redirect
- * @extends TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.PostProcessor
- */
-TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.Redirect = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.PostProcessor, {
-	/**
-	 * @cfg {String} processor
-	 *
-	 * The name of this processor
-	 */
-	processor: 'redirect',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				destination: '',
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.Redirect.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-form-postprocessors-redirect', TYPO3.Form.Wizard.Viewport.Left.Form.PostProcessors.Redirect);
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/Prefix.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/Prefix.js
deleted file mode 100644
index 42ae6975ba42c78a28884078c3f8a4cfefe77eed..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Form/Prefix.js
+++ /dev/null
@@ -1,168 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Form');
-
-/**
- * The prefix panel in the accordion of the form tab on the left side
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Form.Prefix
- * @extends Ext.Panel
- */
-TYPO3.Form.Wizard.Viewport.Left.Form.Prefix = Ext.extend(Ext.ux.form.FakeFormPanel, {
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'formwizard-left-form-prefix',
-
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('form_prefix'),
-
-	/** @cfg {String} defaultType
-	 *
-	 * The default xtype of child Components to create in this Container when
-	 * a child item is specified as a raw configuration object,
-	 * rather than as an instantiated Component.
-	 *
-	 * Defaults to 'panel', except Ext.menu.Menu which defaults to 'menuitem',
-	 * and Ext.Toolbar and Ext.ButtonGroup which default to 'button'.
-	 */
-	defaultType: 'textfield',
-
-	/**
-	 * @cfg {Object} element
-	 * The form component
-	 */
-	element: null,
-
-	/**
-	 * @cfg {Boolean} monitorValid If true, the form monitors its valid state client-side and
-	 * regularly fires the clientvalidation event passing that state.
-	 * When monitoring valid state, the FormPanel enables/disables any of its configured
-	 * buttons which have been configured with formBind: true depending
-	 * on whether the form is valid or not. Defaults to false
-	 */
-	monitorValid: true,
-
-	/**
-	 * Constructor
-	 *
-	 * @param config
-	 */
-	constructor: function(config){
-			// Adds the specified events to the list of events which this Observable may fire.
-		this.addEvents({
-			'validation': true
-		});
-
-			// Call our superclass constructor to complete construction process.
-		TYPO3.Form.Wizard.Viewport.Left.Form.Prefix.superclass.constructor.call(this, config);
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the form elements to the tab
-	 */
-	initComponent: function() {
-		var config = {
-			items: [{
-				xtype: 'fieldset',
-				title: '',
-				ref: 'fieldset',
-				autoHeight: true,
-				border: false,
-				defaults: {
-					width: 150,
-					msgTarget: 'side'
-				},
-				defaultType: 'textfieldsubmit',
-				items: [
-					{
-						fieldLabel: TYPO3.l10n.localize('prefix_prefix'),
-						name: 'prefix',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					}
-				]
-			}]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Form.Prefix.superclass.initComponent.apply(this, arguments);
-
-			// Initialize clientvalidation event
-		this.on('clientvalidation', this.validation, this);
-
-			// Fill the form with the configuration values
-		this.fillForm();
-	},
-
-
-	/**
-	 * Store a changed value from the form in the element
-	 *
-	 * @param {Object} field The field which has changed
-	 */
-	storeValue: function(field) {
-		if (field.isValid()) {
-			var fieldName = field.getName();
-
-			var formConfiguration = {};
-			formConfiguration[fieldName] = field.getValue();
-
-			this.element.setConfigurationValue(formConfiguration);
-		}
-	},
-
-	/**
-	 * Fill the form with the configuration of the element
-	 *
-	 * @param record The current question
-	 * @return void
-	 */
-	fillForm: function() {
-		this.getForm().setValues(this.element.configuration);
-	},
-
-	/**
-	 * Called by the clientvalidation event
-	 *
-	 * Adds or removes the error class if the form is valid or not
-	 *
-	 * @param {Object} formPanel This formpanel
-	 * @param {Boolean} valid True if the client validation is true
-	 */
-	validation: function(formPanel, valid) {
-		if (this.el) {
-			if (valid && this.el.hasClass('validation-error')) {
-				this.removeClass('validation-error');
-				this.fireEvent('validation', 'prefix', valid);
-			} else if (!valid && !this.el.hasClass('validation-error')) {
-				this.addClass('validation-error');
-				this.fireEvent('validation', 'prefix', valid);
-			}
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-form-prefix', TYPO3.Form.Wizard.Viewport.Left.Form.Prefix);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options.js
deleted file mode 100644
index 6e51602abec2628b4ab5684865e443084e9dc6a5..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options.js
+++ /dev/null
@@ -1,170 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.LeftTYPO3.Form.Wizard.Elements');
-
-/**
- * The options tab on the left side
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options
- * @extends Ext.Panel
- */
-TYPO3.Form.Wizard.Viewport.Left.Options = Ext.extend(Ext.Panel, {
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'formwizard-left-options',
-
-	/**
-	 * @cfg {String} cls
-	 * An optional extra CSS class that will be added to this component's
-	 * Element (defaults to ''). This can be useful for adding customized styles
-	 * to the component or any of its children using standard CSS rules.
-	 */
-	cls: 'x-tab-panel-body-content',
-
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('left_options'),
-
-	/**
-	 * @cfg {Boolean} border
-	 * True to display the borders of the panel's body element, false to hide
-	 * them (defaults to true). By default, the border is a 2px wide inset
-	 * border, but this can be further altered by setting bodyBorder to false.
-	 */
-	border: false,
-
-	/**
-	 * @cfg {Number/String} padding
-	 * A shortcut for setting a padding style on the body element. The value can
-	 * either be a number to be applied to all sides, or a normal css string
-	 * describing padding.
-	 */
-	padding: 0,
-
-	/**
-	 * @cfg {Object} validAccordions
-	 * Keeps track which accordions are valid. Accordions contain forms which
-	 * do client validation. If there is a validation change in a form in the
-	 * accordion, a validation event will be fired, which changes one of these
-	 * values
-	 */
-	validAccordions: {
-		attributes: true,
-		filters: true,
-		label: true,
-		legend: true,
-		options: true,
-		validation: true,
-		various: true
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the form elements to the tab
-	 */
-	initComponent: function() {
-		var config = {
-			items: [{
-				xtype: 'typo3-form-wizard-viewport-left-options-dummy'
-			}]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Options.superclass.initComponent.apply(this, arguments);
-
-			// if the active element changes in helper, this should be reflected here
-		TYPO3.Form.Wizard.Helpers.Element.on('setactive', this.toggleActive, this);
-	},
-
-	/**
-	 * Load options form according to element type
-	 *
-	 * This will be called whenever the current element changes
-	 *
-	 * @param component The current element
-	 * @return void
-	 */
-	toggleActive: function(component) {
-		if (component) {
-			this.removeAll();
-			this.add({
-				xtype: 'typo3-form-wizard-viewport-left-options-panel',
-				element: component,
-				listeners: {
-					'validation': {
-						fn: this.validation,
-						scope: this
-					}
-				}
-			});
-			this.ownerCt.setOptionsTab();
-		} else {
-			this.removeAll();
-			this.add({
-				xtype: 'typo3-form-wizard-viewport-left-options-dummy'
-			});
-		}
-		Ext.get(this.tabEl).removeClass('validation-error');
-		Ext.iterate(this.validAccordions, function(key, value) {
-			this.validAccordions[key] = true;
-		}, this);
-		this.doLayout();
-	},
-
-	/**
-	 * Checks if a tab is valid by iterating all accordions on validity
-	 *
-	 * @returns {Boolean}
-	 */
-	tabIsValid: function() {
-		var valid = true;
-
-		Ext.iterate(this.validAccordions, function(key, value) {
-			if (!value) {
-				valid = false;
-			}
-		}, this);
-
-		return valid;
-	},
-
-	/**
-	 * Called by the validation listeners of the accordions
-	 *
-	 * Checks if all accordions are valid. If not, adds a class to the tab
-	 *
-	 * @param {String} accordion The accordion which fires the event
-	 * @param {Boolean} isValid Accordion is valid or not
-	 */
-	validation: function(accordion, isValid) {
-		this.validAccordions[accordion] = isValid;
-		var tabIsValid = this.tabIsValid();
-
-		if (this.tabEl) {
-			var tabEl = Ext.get(this.tabEl);
-			if (tabIsValid && tabEl.hasClass('validation-error')) {
-				tabEl.removeClass('validation-error');
-			} else if (!tabIsValid && !tabEl.hasClass('validation-error')) {
-				tabEl.addClass('validation-error');
-			}
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options', TYPO3.Form.Wizard.Viewport.Left.Options);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Dummy.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Dummy.js
deleted file mode 100644
index 9a40ae1b74e9c494b783850616ed707f2ced94a8..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Dummy.js
+++ /dev/null
@@ -1,65 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options');
-
-/**
- * The options panel for a dummy item
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Dummy
- * @extends Ext.Panel
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Dummy = Ext.extend(Ext.Panel, {
-	/**
-	 * @cfg {Boolean} border
-	 * True to display the borders of the panel's body element, false to hide
-	 * them (defaults to true). By default, the border is a 2px wide inset
-	 * border, but this can be further altered by setting bodyBorder to false.
-	 */
-	border: false,
-
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'formwizard-left-options-dummy',
-
-	/**
-	 * @cfg {String} cls
-	 * An optional extra CSS class that will be added to this component's
-	 * Element (defaults to ''). This can be useful for adding customized styles
-	 * to the component or any of its children using standard CSS rules.
-	 */
-	cls: 'formwizard-left-dummy typo3-message message-information',
-
-	/**
-	 * @cfg {Mixed} data
-	 * The initial set of data to apply to the tpl to update the content area of
-	 * the Component.
-	 */
-	data: [{
-		title: TYPO3.l10n.localize('options_dummy_title'),
-		description: TYPO3.l10n.localize('options_dummy_description')
-	}],
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<tpl for=".">',
-			'<p><strong>{title}</strong></p>',
-			'<p>{description}</p>',
-		'</tpl>'
-	)
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-dummy', TYPO3.Form.Wizard.Viewport.Left.Options.Dummy);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Attributes.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Attributes.js
deleted file mode 100644
index a45bb1183d2b6f9755276e2801b4abc6859242ac..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Attributes.js
+++ /dev/null
@@ -1,1149 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms');
-
-/**
- * The attributes properties of the element
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Attributes
- * @extends Ext.FormPanel
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Attributes = Ext.extend(Ext.ux.form.FakeFormPanel, {
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('options_attributes'),
-
-	/** @cfg {String} defaultType
-	 *
-	 * The default xtype of child Components to create in this Container when
-	 * a child item is specified as a raw configuration object,
-	 * rather than as an instantiated Component.
-	 *
-	 * Defaults to 'panel', except Ext.menu.Menu which defaults to 'menuitem',
-	 * and Ext.Toolbar and Ext.ButtonGroup which default to 'button'.
-	 */
-	defaultType: 'textfieldsubmit',
-
-	/**
-	 * @cfg {Boolean} monitorValid If true, the form monitors its valid state client-side and
-	 * regularly fires the clientvalidation event passing that state.
-	 * When monitoring valid state, the FormPanel enables/disables any of its configured
-	 * buttons which have been configured with formBind: true depending
-	 * on whether the form is valid or not. Defaults to false
-	 */
-	monitorValid: true,
-
-	/**
-	 * Constructor
-	 *
-	 * @param config
-	 */
-	constructor: function(config){
-			// Adds the specified events to the list of events which this Observable may fire.
-		this.addEvents({
-			'validation': true
-		});
-
-			// Call our superclass constructor to complete construction process.
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Attributes.superclass.constructor.call(this, config);
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the form elements to the accordion
-	 */
-	initComponent: function() {
-		var attributes = this.getAttributesBySettings();
-		var formItems = new Array();
-
-		Ext.iterate(attributes, function(item, index, allItems) {
-			switch(item) {
-				case 'accept':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_accept'),
-						name: 'accept',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'accept-charset':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_acceptcharset'),
-						name: 'accept-charset',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'accesskey':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_accesskey'),
-						name: 'accesskey',
-						maxlength: 1,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'action':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_action'),
-						name: 'action',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'alt':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_alt'),
-						name: 'alt',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'autocomplete':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_autocomplete'),
-						name: 'autocomplete',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'autocomplete',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('attributes_autocomplete_none'), value: ''},
-								{label: TYPO3.l10n.localize('attributes_autocomplete_off'), value: 'off'},
-								{label: TYPO3.l10n.localize('attributes_autocomplete_on'), value: 'on'}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'autofocus':
-					formItems.push({
-						xtype: 'typo3-form-wizard-valuecheckbox',
-						fieldLabel: TYPO3.l10n.localize('attributes_autofocus'),
-						name: 'autofocus',
-						inputValue: 'autofocus',
-						listeners: {
-							'check': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'checked':
-					formItems.push({
-						xtype: 'typo3-form-wizard-valuecheckbox',
-						fieldLabel: TYPO3.l10n.localize('attributes_checked'),
-						name: 'checked',
-						inputValue: 'checked',
-						listeners: {
-							'check': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'class':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_class'),
-						name: 'class',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'cols':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_cols'),
-						name: 'cols',
-						xtype: 'spinnerfield',
-						allowBlank: false,
-						listeners: {
-							'spin': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'contenteditable':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_contenteditable'),
-						name: 'contenteditable',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'contenteditable',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('attributes_contenteditable_none'), value: ''},
-								{label: TYPO3.l10n.localize('attributes_contenteditable_true'), value: 'true'},
-								{label: TYPO3.l10n.localize('attributes_contenteditable_false'), value: 'false'}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'contextmenu':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_contextmenu'),
-						name: 'contextmenu',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'dir':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_dir'),
-						name: 'dir',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'dir',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('attributes_dir_ltr'), value: 'ltr'},
-								{label: TYPO3.l10n.localize('attributes_dir_rtl'), value: 'rtl'}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'disabled':
-					formItems.push({
-						xtype: 'typo3-form-wizard-valuecheckbox',
-						fieldLabel: TYPO3.l10n.localize('attributes_disabled'),
-						name: 'disabled',
-						inputValue: 'disabled',
-						listeners: {
-							'check': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'draggable':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_draggable'),
-						name: 'draggable',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'draggable',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('attributes_draggable_none'), value: ''},
-								{label: TYPO3.l10n.localize('attributes_draggable_false'), value: 'false'},
-								{label: TYPO3.l10n.localize('attributes_draggable_true'), value: 'true'},
-								{label: TYPO3.l10n.localize('attributes_draggable_auto'), value: 'auto'}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'dropzone':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_dropzone'),
-						name: 'dropzone',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'enctype':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_enctype'),
-						name: 'enctype',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'enctype',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('attributes_enctype_1'), value: 'application/x-www-form-urlencoded'},
-								{label: TYPO3.l10n.localize('attributes_enctype_2'), value: 'multipart/form-data'},
-								{label: TYPO3.l10n.localize('attributes_enctype_3'), value: 'text/plain'}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'height':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_height'),
-						name: 'height',
-						xtype: 'spinnerfield',
-						listeners: {
-							'spin': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'hidden':
-					formItems.push({
-						xtype: 'typo3-form-wizard-valuecheckbox',
-						fieldLabel: TYPO3.l10n.localize('attributes_hidden'),
-						name: 'hidden',
-						inputValue: 'hidden',
-						listeners: {
-							'check': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'id':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_id'),
-						name: 'id',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'inputmode':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_inputmode'),
-						name: 'inputmode',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'inputmode',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('attributes_inputmode_none'), value: ''},
-								{label: TYPO3.l10n.localize('attributes_inputmode_verbatim'), value: 'verbatim'},
-								{label: TYPO3.l10n.localize('attributes_inputmode_latin'), value: 'latin'},
-								{label: TYPO3.l10n.localize('attributes_inputmode_latin-name'), value: 'latin-name'},
-								{label: TYPO3.l10n.localize('attributes_inputmode_latin-prose'), value: 'latin-prose'},
-								{label: TYPO3.l10n.localize('attributes_inputmode_full-width-latin'), value: 'full-width-latin'},
-								{label: TYPO3.l10n.localize('attributes_inputmode_kana'), value: 'kana'},
-								{label: TYPO3.l10n.localize('attributes_inputmode_kana-name'), value: 'kana-name'},
-								{label: TYPO3.l10n.localize('attributes_inputmode_katakana'), value: 'katakana'},
-								{label: TYPO3.l10n.localize('attributes_inputmode_numeric'), value: 'numeric'},
-								{label: TYPO3.l10n.localize('attributes_inputmode_tel'), value: 'tel'},
-								{label: TYPO3.l10n.localize('attributes_inputmode_email'), value: 'email'},
-								{label: TYPO3.l10n.localize('attributes_inputmode_url'), value: 'url'}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'label':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_label'),
-						name: 'label',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'lang':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_lang'),
-						name: 'lang',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'list':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_list'),
-						name: 'list',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'max':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_max'),
-						name: 'max',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'maxlength':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_maxlength'),
-						name: 'maxlength',
-						xtype: 'spinnerfield',
-						listeners: {
-							'spin': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'method':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_method'),
-						name: 'method',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'method',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('attributes_method_get'), value: 'get'},
-								{label: TYPO3.l10n.localize('attributes_method_post'), value: 'post'}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'min':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_min'),
-						name: 'min',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'minlength':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_minlength'),
-						name: 'minlength',
-						xtype: 'spinnerfield',
-						listeners: {
-							'spin': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'multiple':
-					formItems.push({
-						xtype: 'typo3-form-wizard-valuecheckbox',
-						fieldLabel: TYPO3.l10n.localize('attributes_multiple'),
-						name: 'multiple',
-						inputValue: 'multiple',
-						listeners: {
-							'check': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'name':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_name'),
-						name: 'name',
-						allowBlank:false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'novalidate':
-					formItems.push({
-						xtype: 'typo3-form-wizard-valuecheckbox',
-						fieldLabel: TYPO3.l10n.localize('attributes_novalidate'),
-						name: 'novalidate',
-						inputValue: 'novalidate',
-						listeners: {
-							'check': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'pattern':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_pattern'),
-						name: 'pattern',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'placeholder':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_placeholder'),
-						name: 'placeholder',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'readonly':
-					formItems.push({
-						xtype: 'typo3-form-wizard-valuecheckbox',
-						fieldLabel: TYPO3.l10n.localize('attributes_readonly'),
-						name: 'readonly',
-						inputValue: 'readonly',
-						listeners: {
-							'check': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'required':
-					formItems.push({
-						xtype: 'typo3-form-wizard-valuecheckbox',
-						fieldLabel: TYPO3.l10n.localize('attributes_required'),
-						name: 'required',
-						inputValue: 'required',
-						listeners: {
-							'check': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'rows':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_rows'),
-						name: 'rows',
-						xtype: 'spinnerfield',
-						allowBlank: false,
-						listeners: {
-							'spin': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'selected':
-					formItems.push({
-						xtype: 'typo3-form-wizard-valuecheckbox',
-						fieldLabel: TYPO3.l10n.localize('attributes_selected'),
-						name: 'selected',
-						inputValue: 'selected',
-						listeners: {
-							'check': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'selectionDirection':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_selectionDirection'),
-						name: 'selectionDirection',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'selectionDirection',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('attributes_selectionDirection_none'), value: ''},
-								{label: TYPO3.l10n.localize('attributes_selectionDirection_forward'), value: 'forward'},
-								{label: TYPO3.l10n.localize('attributes_selectionDirection_backward'), value: 'backward'}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'selectionEnd':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_selectionEnd'),
-						name: 'selectionEnd',
-						xtype: 'spinnerfield',
-						listeners: {
-							'spin': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'selectionStart':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_selectionStart'),
-						name: 'selectionStart',
-						xtype: 'spinnerfield',
-						listeners: {
-							'spin': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'size':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_size'),
-						name: 'size',
-						xtype: 'spinnerfield',
-						listeners: {
-							'spin': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'spellcheck':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_spellcheck'),
-						name: 'spellcheck',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'spellcheck',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('attributes_spellcheck_none'), value: ''},
-								{label: TYPO3.l10n.localize('attributes_spellcheck_true'), value: 'true'},
-								{label: TYPO3.l10n.localize('attributes_spellcheck_false'), value: 'false'}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'src':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_src'),
-						name: 'src',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'step':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_step'),
-						name: 'step',
-						xtype: 'spinnerfield',
-						listeners: {
-							'spin': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'style':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_style'),
-						name: 'style',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'tabindex':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_tabindex'),
-						name: 'tabindex',
-						xtype: 'spinnerfield',
-						listeners: {
-							'spin': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'text':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_text'),
-						xtype: 'textarea',
-						name: 'text',
-						allowBlank: true,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'title':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_title'),
-						name: 'title',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'translate':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_translate'),
-						name: 'translate',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'translate',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('attributes_translate_none'), value: ''},
-								{label: TYPO3.l10n.localize('attributes_translate_no'), value: 'no'},
-								{label: TYPO3.l10n.localize('attributes_translate_yes'), value: 'yes'}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'type':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_type'),
-						name: 'type',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'type',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('attributes_type_color'), value: 'color'},
-								{label: TYPO3.l10n.localize('attributes_type_date'), value: 'date'},
-								{label: TYPO3.l10n.localize('attributes_type_datetime'), value: 'datetime'},
-								{label: TYPO3.l10n.localize('attributes_type_datetime-local'), value: 'datetime-local'},
-								{label: TYPO3.l10n.localize('attributes_type_email'), value: 'email'},
-								{label: TYPO3.l10n.localize('attributes_type_month'), value: 'month'},
-								{label: TYPO3.l10n.localize('attributes_type_number'), value: 'number'},
-								{label: TYPO3.l10n.localize('attributes_type_search'), value: 'search'},
-								{label: TYPO3.l10n.localize('attributes_type_tel'), value: 'tel'},
-								{label: TYPO3.l10n.localize('attributes_type_text'), value: 'text'},
-								{label: TYPO3.l10n.localize('attributes_type_time'), value: 'time'},
-								{label: TYPO3.l10n.localize('attributes_type_url'), value: 'url'},
-								{label: TYPO3.l10n.localize('attributes_type_week'), value: 'week'}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'value':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_value'),
-						name: 'value',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'width':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_width'),
-						name: 'width',
-						xtype: 'spinnerfield',
-						listeners: {
-							'spin': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'wrap':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('attributes_wrap'),
-						name: 'wrap',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'wrap',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('attributes_wrap_none'), value: ''},
-								{label: TYPO3.l10n.localize('attributes_wrap_soft'), value: 'soft'},
-								{label: TYPO3.l10n.localize('attributes_wrap_hard'), value: 'hard'}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-			}
-		}, this);
-
-		var config = {
-			items: [{
-				xtype: 'fieldset',
-				title: '',
-				autoHeight: true,
-				border: false,
-				defaults: {
-					width: 150,
-					msgTarget: 'side'
-				},
-				defaultType: 'textfieldsubmit',
-				items: formItems
-			}]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Attributes.superclass.initComponent.apply(this, arguments);
-
-			// Initialize clientvalidation event
-		this.on('clientvalidation', this.validation, this);
-
-			// Fill the form with the configuration values
-		this.fillForm();
-	},
-
-	/**
-	 * Store a changed value from the form in the element
-	 *
-	 * @param {Object} field The field which has changed
-	 */
-	storeValue: function(field) {
-		if (field.isValid()) {
-			var fieldName = field.getName();
-
-			var formConfiguration = {attributes: {}};
-			formConfiguration.attributes[fieldName] = field.getValue();
-
-			this.element.setConfigurationValue(formConfiguration);
-		}
-	},
-
-	/**
-	 * Fill the form with the configuration of the element
-	 *
-	 * @return void
-	 */
-	fillForm: function() {
-		this.getForm().setValues(this.element.configuration.attributes);
-	},
-
-	/**
-	 * Get the attributes for the element
-	 *
-	 * Based on the elements attributes, the TSconfig general allowed attributes
-	 * and the TSconfig allowed attributes for this type of element
-	 *
-	 * @returns object
-	 */
-	getAttributesBySettings: function() {
-		var attributes = [];
-		var elementAttributes = this.element.configuration.attributes;
-		var elementType = this.element.xtype.split('-').pop();
-
-		var allowedGeneralAttributes = [];
-		try {
-			allowedGeneralAttributes = TYPO3.Form.Wizard.Settings.defaults.tabs.options.accordions.attributes.showProperties.split(/[, ]+/);
-		} catch (error) {
-			// The object has not been found or constructed wrong
-			allowedGeneralAttributes = [
-				'accept',
-				'acceptcharset',
-				'accesskey',
-				'action',
-				'alt',
-				'checked',
-				'class',
-				'cols',
-				'dir',
-				'disabled',
-				'enctype',
-				'id',
-				'label',
-				'lang',
-				'maxlength',
-				'method',
-				'multiple',
-				'name',
-				'readonly',
-				'rows',
-				'selected',
-				'size',
-				'src',
-				'style',
-				'tabindex',
-				'title',
-				'type',
-				'value'
-			];
-		}
-
-		var allowedElementAttributes = [];
-		try {
-			allowedElementAttributes = TYPO3.Form.Wizard.Settings.elements[elementType].accordions.attributes.showProperties.split(/[, ]+/);
-		} catch (error) {
-			// The object has not been found
-			allowedElementAttributes = allowedGeneralAttributes;
-		}
-
-		Ext.iterate(allowedElementAttributes, function(item, index, allItems) {
-			if (allowedGeneralAttributes.indexOf(item) > -1 && Ext.isDefined(elementAttributes[item])) {
-				attributes.push(item);
-			}
-		}, this);
-
-		return attributes;
-	},
-
-	/**
-	 * Called by the clientvalidation event
-	 *
-	 * Adds or removes the error class if the form is valid or not
-	 *
-	 * @param {Object} formPanel This formpanel
-	 * @param {Boolean} valid True if the client validation is true
-	 */
-	validation: function(formPanel, valid) {
-		if (this.el) {
-			if (valid && this.el.hasClass('validation-error')) {
-				this.removeClass('validation-error');
-				this.fireEvent('validation', 'attributes', valid);
-			} else if (!valid && !this.el.hasClass('validation-error')) {
-				this.addClass('validation-error');
-				this.fireEvent('validation', 'attributes', valid);
-			}
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-attributes', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Attributes);
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters.js
deleted file mode 100644
index 0b835f396245b44c697457ddbebff0aafac1ff34..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters.js
+++ /dev/null
@@ -1,243 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms');
-
-/**
- * The filters accordion panel in the element options in the left tabpanel
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters
- * @extends Ext.Panel
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters = Ext.extend(Ext.Panel, {
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('options_filters'),
-
-	/**
-	 * @cfg {Object} validFilters
-	 * Keeps track which filters are valid. Filters contain forms which
-	 * do client validation. If there is a validation change in a form in the
-	 * filter, a validation event will be fired, which changes one of these
-	 * values
-	 */
-	validFilters: {
-		alphabetic: true,
-		alphanumeric: true,
-		currency: true,
-		digit: true,
-		integer: true,
-		lowercase: true,
-		regexp: true,
-		stripnewlines: true,
-		titlecase: true,
-		trim: true,
-		uppercase: true
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the form elements to the accordion
-	 */
-	initComponent: function() {
-		var filters = this.getFiltersBySettings();
-
-			// Adds the specified events to the list of events which this Observable may fire.
-		this.addEvents({
-			'validation': true
-		});
-
-		var config = {
-			items: [{
-				xtype: 'typo3-form-wizard-viewport-left-options-forms-filters-dummy',
-				ref: 'dummy'
-			}],
-			tbar: [
-				{
-					xtype: 'combo',
-					hideLabel: true,
-					name: 'filters',
-					ref: 'filters',
-					mode: 'local',
-					triggerAction: 'all',
-					forceSelection: true,
-					editable: false,
-					hiddenName: 'filters',
-					emptyText: TYPO3.l10n.localize('filters_emptytext'),
-					width: 150,
-					displayField: 'label',
-					valueField: 'value',
-					store: new Ext.data.JsonStore({
-						fields: ['label', 'value'],
-						data: filters
-					}),
-					listeners: {
-						'select': {
-							scope: this,
-							fn: this.addFilter
-						}
-					}
-				}
-			]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.superclass.initComponent.apply(this, arguments);
-
-			// Initialize the filters when they are available for this element
-		this.initFilters();
-	},
-
-	/**
-	 * Called when constructing the filters accordion
-	 *
-	 * Checks if the element already has filters and loads these instead of the dummy
-	 */
-	initFilters: function() {
-		var filters = this.element.configuration.filters;
-		if (!Ext.isEmptyObject(filters)) {
-			this.remove(this.dummy);
-			Ext.iterate(filters, function(key, value) {
-				this.add({
-					xtype: 'typo3-form-wizard-viewport-left-options-forms-filters-' + key,
-					element: this.element,
-					configuration: value,
-					listeners: {
-						'validation': {
-							fn: this.validation,
-							scope: this
-						}
-					}
-				});
-			}, this);
-		}
-	},
-
-	/**
-	 * Add a filter to the filters list
-	 *
-	 * @param comboBox
-	 * @param record
-	 * @param index
-	 */
-	addFilter: function(comboBox, record, index) {
-		var filter = comboBox.getValue();
-		var xtype = 'typo3-form-wizard-viewport-left-options-forms-filters-' + filter;
-
-		if (!Ext.isEmpty(this.findByType(xtype))) {
-			Ext.MessageBox.alert(TYPO3.l10n.localize('filters_alert_title'), TYPO3.l10n.localize('filters_alert_description'));
-		} else {
-			this.remove(this.dummy);
-
-			this.add({
-				xtype: xtype,
-				element: this.element,
-				listeners: {
-					'validation': {
-						fn: this.validation,
-						scope: this
-					}
-				}
-			});
-			this.doLayout();
-		}
-	},
-
-	/**
-	 * Remove a filter from the filters list
-	 *
-	 * Shows dummy when there is no filter for this element
-	 *
-	 * @param component
-	 */
-	removeFilter: function(component) {
-		this.remove(component);
-		this.validation(component.filter, true);
-		if (this.items.length == 0) {
-			this.add({
-				xtype: 'typo3-form-wizard-viewport-left-options-forms-filters-dummy',
-				ref: 'dummy'
-			});
-		}
-		this.doLayout();
-	},
-
-	/**
-	 * Get the allowed filters by the TSconfig settings
-	 *
-	 * @returns {Array}
-	 */
-	getFiltersBySettings: function() {
-		var filters = [];
-		var elementType = this.element.xtype.split('-').pop();
-
-		var allowedDefaultFilters = [];
-		try {
-			allowedDefaultFilters = TYPO3.Form.Wizard.Settings.defaults.tabs.options.accordions.filtering.showFilters.split(/[, ]+/);
-		} catch (error) {
-			// The object has not been found
-			allowedDefaultFilters = [
-				'alphabetic',
-				'alphanumeric',
-				'currency',
-				'digit',
-				'integer',
-				'lowercase',
-				'regexp',
-				'stripnewlines',
-				'titlecase',
-				'trim',
-				'uppercase'
-			];
-		}
-
-		var allowedElementFilters = [];
-		try {
-			allowedElementFilters = TYPO3.Form.Wizard.Settings.elements[elementType].accordions.filtering.showFilters.split(/[, ]+/);
-		} catch (error) {
-			// The object has not been found or constructed wrong
-			allowedElementFilters = allowedDefaultFilters;
-		}
-
-		Ext.iterate(allowedElementFilters, function(item, index, allItems) {
-			if (allowedDefaultFilters.indexOf(item) > -1) {
-				filters.push({label: TYPO3.l10n.localize('filters_' + item), value: item});
-			}
-		}, this);
-
-		return filters;
-	},
-
-	/**
-	 * Called by the validation listeners of the filters
-	 *
-	 * Checks if all filters are valid. If not, adds a class to the accordion
-	 *
-	 * @param {String} filter The filter which fires the event
-	 * @param {Boolean} isValid Rule is valid or not
-	 */
-	validation: function(filter, isValid) {
-		this.validFilters[filter] = isValid;
-		var accordionIsValid = true;
-		Ext.iterate(this.validFilters, function(key, value) {
-			if (!value) {
-				accordionIsValid = false;
-			}
-		}, this);
-		if (this.el) {
-			if (accordionIsValid && this.el.hasClass('validation-error')) {
-				this.removeClass('validation-error');
-				this.fireEvent('validation', 'filters', isValid);
-			} else if (!accordionIsValid && !this.el.hasClass('validation-error')) {
-				this.addClass('validation-error');
-				this.fireEvent('validation', 'filters', isValid);
-			}
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-filters', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Alphabetic.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Alphabetic.js
deleted file mode 100644
index ae12e8e3480b9102456b6132b0efd1b7e4cd5322..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Alphabetic.js
+++ /dev/null
@@ -1,33 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters');
-
-/**
- * The alphabetic filter
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Alphabetic
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Alphabetic = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter, {
-	/**
-	 * @cfg {String} filter
-	 *
-	 * The name of this filter
-	 */
-	filter: 'alphabetic',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				allowWhiteSpace: 0
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Alphabetic.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-filters-alphabetic', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Alphabetic);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Alphanumeric.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Alphanumeric.js
deleted file mode 100644
index 1929ac1addf5144ca7043a5b44b8a1c292214d21..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Alphanumeric.js
+++ /dev/null
@@ -1,33 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters');
-
-/**
- * The alphanumeric filter
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Alphanumeric
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Alphanumeric = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter, {
-	/**
-	 * @cfg {String} filter
-	 *
-	 * The name of this filter
-	 */
-	filter: 'alphanumeric',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				allowWhiteSpace: 0
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Alphanumeric.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-filters-alphanumeric', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Alphanumeric);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Currency.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Currency.js
deleted file mode 100644
index 3878dc6738fff6f2c3d46b4324f575121a96716d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Currency.js
+++ /dev/null
@@ -1,34 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters');
-
-/**
- * The currency filter
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Currency
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Currency = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter, {
-	/**
-	 * @cfg {String} filter
-	 *
-	 * The name of this filter
-	 */
-	filter: 'currency',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				decimalPoint: '.',
-				thousandSeparator: ','
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Currency.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-filters-currency', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Currency);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Digit.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Digit.js
deleted file mode 100644
index 4fd4c4804d45e85e07ce61a9d2251d70f85a2845..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Digit.js
+++ /dev/null
@@ -1,18 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters');
-
-/**
- * The digit filter
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Digit
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Digit = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter, {
-	/**
-	 * @cfg {String} filter
-	 *
-	 * The name of this filter
-	 */
-	filter: 'digit'
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-filters-digit', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Digit);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Dummy.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Dummy.js
deleted file mode 100644
index f8b71a3f812647bcaadd4d8dc7e053b39fd31d9e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Dummy.js
+++ /dev/null
@@ -1,58 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters');
-
-/**
- * The dummy item when no filter is defined for an element
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Dummy
- * @extends Ext.Panel
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Dummy = Ext.extend(Ext.Panel, {
-	/**
-	 * @cfg {Boolean} border
-	 * True to display the borders of the panel's body element, false to hide
-	 * them (defaults to true). By default, the border is a 2px wide inset
-	 * border, but this can be further altered by setting bodyBorder to false.
-	 */
-	border: false,
-
-	/**
-	 * @cfg {Number/String} padding
-	 * A shortcut for setting a padding style on the body element. The value can
-	 * either be a number to be applied to all sides, or a normal css string
-	 * describing padding.
-	 */
-	padding: 0,
-
-	/**
-	 * @cfg {String} cls
-	 * An optional extra CSS class that will be added to this component's
-	 * Element (defaults to ''). This can be useful for adding customized styles
-	 * to the component or any of its children using standard CSS rules.
-	 */
-	cls: 'formwizard-left-dummy typo3-message message-information',
-
-	/**
-	 * @cfg {Mixed} data
-	 * The initial set of data to apply to the tpl to update the content area of
-	 * the Component.
-	 */
-	data: [{
-		title: TYPO3.l10n.localize('filters_dummy_title'),
-		description: TYPO3.l10n.localize('filters_dummy_description')
-	}],
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<tpl for=".">',
-			'<p><strong>{title}</strong></p>',
-			'<p>{description}</p>',
-		'</tpl>'
-	)
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-filters-dummy', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Dummy);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Filter.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Filter.js
deleted file mode 100644
index 3592489c6c1ba8437f7018f1792c98980cd026d6..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Filter.js
+++ /dev/null
@@ -1,345 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters');
-
-/**
- * The filter abstract
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter
- * @extends Ext.FormPanel
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter = Ext.extend(Ext.ux.form.FakeFormPanel, {
-	/**
-	 * @cfg {Boolean} border
-	 * True to display the borders of the panel's body element, false to hide
-	 * them (defaults to true). By default, the border is a 2px wide inset
-	 * border, but this can be further altered by setting bodyBorder to false.
-	 */
-	border: false,
-
-	/**
-	 * @cfg {Number/String} padding
-	 * A shortcut for setting a padding style on the body element. The value can
-	 * either be a number to be applied to all sides, or a normal css string
-	 * describing padding.
-	 */
-	padding: 0,
-
-	/**
-	 * @cfg {String} defaultType
-	 *
-	 * The default xtype of child Components to create in this Container when
-	 * a child item is specified as a raw configuration object,
-	 * rather than as an instantiated Component.
-	 *
-	 * Defaults to 'panel', except Ext.menu.Menu which defaults to 'menuitem',
-	 * and Ext.Toolbar and Ext.ButtonGroup which default to 'button'.
-	 */
-	defaultType: 'textfield',
-
-	/**
-	 * @cfg {Boolean} monitorValid If true, the form monitors its valid state client-side and
-	 * regularly fires the clientvalidation event passing that state.
-	 * When monitoring valid state, the FormPanel enables/disables any of its configured
-	 * buttons which have been configured with formBind: true depending
-	 * on whether the form is valid or not. Defaults to false
-	 */
-	monitorValid: true,
-
-	/**
-	 * @cfg {Object} Default filter configuration
-	 */
-	configuration: {},
-
-	/**
-	 * Constructor
-	 */
-	initComponent: function() {
-		var fields = this.getFieldsBySettings();
-		var formItems = new Array();
-
-			// Adds the specified events to the list of events which this Observable may fire.
-		this.addEvents({
-			'validation': true
-		});
-
-		Ext.iterate(fields, function(item, index, allItems) {
-			switch(item) {
-				case 'allowWhiteSpace':
-					formItems.push({
-						xtype: 'checkbox',
-						fieldLabel: TYPO3.l10n.localize('filters_properties_allowwhitespace'),
-						name: 'allowWhiteSpace',
-						inputValue: '1',
-						listeners: {
-							'check': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'decimalPoint':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('filters_properties_decimalpoint'),
-						name: 'decimalPoint',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'thousandSeparator':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('filters_properties_thousandseparator'),
-						name: 'thousandSeparator',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'expression':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('filters_properties_expression'),
-						name: 'expression',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'characterList':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('filters_properties_characterlist'),
-						name: 'characterList',
-						allowBlank: true,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-			}
-		}, this);
-
-		if (Ext.isEmpty(formItems)) {
-			formItems.push({
-				xtype: 'box',
-				autoEl: {
-					tag: 'div'
-				},
-				width: 256,
-				cls: 'typo3-message message-information',
-				data: [{
-					title: TYPO3.l10n.localize('filters_properties_none_title'),
-					description: TYPO3.l10n.localize('filters_properties_none')
-				}],
-				tpl: new Ext.XTemplate(
-					'<tpl for=".">',
-						'<p><strong>{title}</strong></p>',
-						'<p>{description}</p>',
-					'</tpl>'
-				)
-
-			});
-		}
-
-		formItems.push({
-			xtype: 'button',
-			text: TYPO3.l10n.localize('button_remove'),
-			handler: this.removeFilter,
-			scope: this
-		});
-
-		var config = {
-			items: [
-				{
-					xtype: 'fieldset',
-					title: this.filter,
-					autoHeight: true,
-					defaults: {
-						width: 128,
-						msgTarget: 'side'
-					},
-					defaultType: 'textfieldsubmit',
-					items: formItems
-				}
-			]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter.superclass.initComponent.apply(this, arguments);
-
-			// Initialize clientvalidation event
-		this.on('clientvalidation', this.validation, this);
-
-			// Strange, but we need to call doLayout() after render
-		this.on('afterrender', this.newOrExistingFilter, this);
-	},
-
-	/**
-	 * Decide whether this is a new or an existing one
-	 *
-	 * If new, the default configuration has to be added to the filters
-	 * of the element, otherwise we can fill the form with the existing configuration
-	 */
-	newOrExistingFilter: function() {
-		this.doLayout();
-			// Existing filter
-		if (this.element.configuration.filters[this.filter]) {
-			this.fillForm();
-			// New filter
-		} else {
-			this.addFilterToElement();
-		}
-	},
-
-	/**
-	 * Fill the form with the configuration of the element
-	 *
-	 * When filling, the events of all form elements should be suspended,
-	 * otherwise the values are written back to the element, for instance on a
-	 * check event on a checkbox.
-	 */
-	fillForm: function() {
-		this.suspendEventsBeforeFilling();
-		this.getForm().setValues(this.element.configuration.filters[this.filter]);
-		this.resumeEventsAfterFilling();
-	},
-
-	/**
-	 * Suspend the events on all items within this component
-	 */
-	suspendEventsBeforeFilling: function() {
-		this.cascade(function(item) {
-			item.suspendEvents();
-		});
-	},
-
-	/**
-	 * Resume the events on all items within this component
-	 */
-	resumeEventsAfterFilling: function() {
-		this.cascade(function(item) {
-			item.resumeEvents();
-		});
-	},
-
-	/**
-	 * Add this filter to the element
-	 */
-	addFilterToElement: function() {
-		var formConfiguration = {filters: {}};
-		formConfiguration.filters[this.filter] = this.configuration;
-
-		this.element.setConfigurationValue(formConfiguration);
-
-		this.fillForm();
-	},
-
-	/**
-	 * Store a changed value from the form in the element
-	 *
-	 * @param {Object} field The field which has changed
-	 */
-	storeValue: function(field) {
-		if (field.isValid()) {
-			var fieldName = field.getName();
-
-			var formConfiguration = {filters: {}};
-			formConfiguration.filters[this.filter] = {};
-			formConfiguration.filters[this.filter][fieldName] = field.getValue();
-
-			this.element.setConfigurationValue(formConfiguration);
-		}
-	},
-
-	/**
-	 * Remove the filter
-	 *
-	 * Called when the remove button of this filter has been clicked
-	 */
-	removeFilter: function() {
-		this.ownerCt.removeFilter(this);
-		this.element.removeFilter(this.filter);
-	},
-
-	/**
-	 * Get the fields for the element
-	 *
-	 * Based on the TSconfig general allowed fields
-	 * and the TSconfig allowed fields for this type of element
-	 *
-	 * @returns object
-	 */
-	getFieldsBySettings: function() {
-		var fields = [];
-		var filterFields = this.configuration;
-		var elementType = this.element.xtype.split('-').pop();
-
-		var allowedGeneralFields = [];
-		try {
-			allowedGeneralFields = TYPO3.Form.Wizard.Settings.defaults.tabs.options.accordions.filtering.filters[this.filter].showProperties.split(/[, ]+/);
-		} catch (error) {
-			// The object has not been found or constructed wrong
-			allowedGeneralFields = [
-				'allowWhiteSpace',
-				'decimalPoint',
-				'thousandSeparator',
-				'expression',
-				'characterList'
-			];
-		}
-
-		var allowedElementFields = [];
-		try {
-			allowedElementFields = TYPO3.Form.Wizard.Settings.elements[elementType].accordions.filtering.filters[this.filter].showProperties.split(/[, ]+/);
-		} catch (error) {
-			// The object has not been found or constructed wrong
-			allowedElementFields = allowedGeneralFields;
-		}
-
-		Ext.iterate(allowedElementFields, function(item, index, allItems) {
-			if (allowedGeneralFields.indexOf(item) > -1 && Ext.isDefined(filterFields[item])) {
-				fields.push(item);
-			}
-		}, this);
-
-		return fields;
-	},
-
-	/**
-	 * Called by the clientvalidation event
-	 *
-	 * Adds or removes the error class if the form is valid or not
-	 *
-	 * @param {Object} formPanel This formpanel
-	 * @param {Boolean} valid True if the client validation is true
-	 */
-	validation: function(formPanel, valid) {
-		if (this.el) {
-			if (valid && this.el.hasClass('validation-error')) {
-				this.removeClass('validation-error');
-				this.fireEvent('validation', this.filter, valid);
-			} else if (!valid && !this.el.hasClass('validation-error')) {
-				this.addClass('validation-error');
-				this.fireEvent('validation', this.filter, valid);
-			}
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-filters-filter', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Integer.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Integer.js
deleted file mode 100644
index a2931b6d6aefed24e322d226220d17aa7f19ec2b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Integer.js
+++ /dev/null
@@ -1,18 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters');
-
-/**
- * The integer filter
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Integer
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Integer = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter, {
-	/**
-	 * @cfg {String} filter
-	 *
-	 * The name of this filter
-	 */
-	filter: 'integer'
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-filters-integer', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Integer);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/LowerCase.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/LowerCase.js
deleted file mode 100644
index 96f2ac09cbf52da64d3a0a7319e0423e76377c7e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/LowerCase.js
+++ /dev/null
@@ -1,18 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters');
-
-/**
- * The lower case filter
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.LowerCase
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.LowerCase = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter, {
-	/**
-	 * @cfg {String} filter
-	 *
-	 * The name of this filter
-	 */
-	filter: 'lowercase'
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-filters-lowercase', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.LowerCase);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/RegExp.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/RegExp.js
deleted file mode 100644
index 242fdb6dc33a77f16621f0c306aa8ebd17058438..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/RegExp.js
+++ /dev/null
@@ -1,33 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters');
-
-/**
- * The regular expression filter
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.RegExp
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.RegExp = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter, {
-	/**
-	 * @cfg {String} filter
-	 *
-	 * The name of this filter
-	 */
-	filter: 'regexp',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				expression: ''
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.RegExp.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-filters-regexp', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.RegExp);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/StripNewLines.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/StripNewLines.js
deleted file mode 100644
index c37ced00a713241e459de4d5dbc83f913daa1b05..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/StripNewLines.js
+++ /dev/null
@@ -1,18 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters');
-
-/**
- * The strip new lines filter
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.StripNewLines
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.StripNewLines = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter, {
-	/**
-	 * @cfg {String} filter
-	 *
-	 * The name of this filter
-	 */
-	filter: 'stripnewlines'
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-filters-stripnewlines', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.StripNewLines);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/TitleCase.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/TitleCase.js
deleted file mode 100644
index df367ce4bb47418a3b0f9e7db0c33728959dff9b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/TitleCase.js
+++ /dev/null
@@ -1,18 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters');
-
-/**
- * The title case filter
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.TitleCase
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.TitleCase = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter, {
-	/**
-	 * @cfg {String} filter
-	 *
-	 * The name of this filter
-	 */
-	filter: 'titlecase'
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-filters-titlecase', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.TitleCase);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Trim.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Trim.js
deleted file mode 100644
index 32c9a4b4c7e959e494daa18c8a2d87d922fa4807..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/Trim.js
+++ /dev/null
@@ -1,33 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters');
-
-/**
- * The trim filter
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Trim
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Trim = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter, {
-	/**
-	 * @cfg {String} filter
-	 *
-	 * The name of this filter
-	 */
-	filter: 'trim',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				characterList: ''
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Trim.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-filters-trim', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Trim);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/UpperCase.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/UpperCase.js
deleted file mode 100644
index 680b40822d3ad971a95034a8e0b09ffa14183a70..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Filters/UpperCase.js
+++ /dev/null
@@ -1,18 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters');
-
-/**
- * The upper case filter
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.UpperCase
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.UpperCase = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.Filter, {
-	/**
-	 * @cfg {String} filter
-	 *
-	 * The name of this filter
-	 */
-	filter: 'uppercase'
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-filters-uppercase', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Filters.UpperCase);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Label.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Label.js
deleted file mode 100644
index 2f46d194ec94878cdbe89ef4ab64cbdee6b81213..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Label.js
+++ /dev/null
@@ -1,229 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms');
-
-/**
- * The label properties and the layout of the element
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Label
- * @extends Ext.FormPanel
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Label = Ext.extend(Ext.ux.form.FakeFormPanel, {
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('options_label'),
-
-	/** @cfg {String} defaultType
-	 *
-	 * The default xtype of child Components to create in this Container when
-	 * a child item is specified as a raw configuration object,
-	 * rather than as an instantiated Component.
-	 *
-	 * Defaults to 'panel', except Ext.menu.Menu which defaults to 'menuitem',
-	 * and Ext.Toolbar and Ext.ButtonGroup which default to 'button'.
-	 */
-	defaultType: 'textfield',
-
-	/**
-	 * @cfg {Boolean} monitorValid If true, the form monitors its valid state client-side and
-	 * regularly fires the clientvalidation event passing that state.
-	 * When monitoring valid state, the FormPanel enables/disables any of its configured
-	 * buttons which have been configured with formBind: true depending
-	 * on whether the form is valid or not. Defaults to false
-	 */
-	monitorValid: true,
-
-	/**
-	 * @cfg {String} cls
-	 * An optional extra CSS class that will be added to this component's
-	 * Element (defaults to ''). This can be useful for adding customized styles
-	 * to the component or any of its children using standard CSS rules.
-	 */
-	cls: 'x-panel-accordion',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the form elements to the accordion
-	 */
-	initComponent: function() {
-		var fields = this.getFieldsBySettings();
-		var formItems = new Array();
-
-			// Adds the specified events to the list of events which this Observable may fire.
-		this.addEvents({
-			'validation': true
-		});
-
-		Ext.iterate(fields, function(item, index, allItems) {
-			switch(item) {
-				case 'label':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('label_label'),
-						name: 'label',
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'layout':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('label_layout'),
-						name: 'layout',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'layout',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('label_layout_front'), value: 'front'},
-								{label: TYPO3.l10n.localize('label_layout_back'), value: 'back'}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				default:
-			}
-		}, this);
-
-		var config = {
-			items: [{
-				xtype: 'fieldset',
-				title: '',
-				border: false,
-				autoHeight: true,
-				defaults: {
-					width: 150,
-					msgTarget: 'side'
-				},
-				defaultType: 'textfieldsubmit',
-				items: formItems
-			}]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Label.superclass.initComponent.apply(this, arguments);
-
-			// Initialize clientvalidation event
-		this.on('clientvalidation', this.validation, this);
-
-			// Fill the form with the configuration values
-		this.fillForm();
-	},
-
-	/**
-	 * Store a changed value from the form in the element
-	 *
-	 * @param {Object} field The field which has changed
-	 */
-	storeValue: function(field) {
-		if (field.isValid()) {
-			var fieldName = field.getName();
-
-			if (fieldName == 'label') {
-				var formConfiguration = {
-					label: {
-						value: field.getValue()
-					}
-				};
-			} else {
-				var formConfiguration = {};
-				formConfiguration[fieldName] = field.getValue();
-			}
-			this.element.setConfigurationValue(formConfiguration);
-		}
-	},
-
-	/**
-	 * Fill the form with the configuration of the element
-	 *
-	 * @param record The current question
-	 * @return void
-	 */
-	fillForm: function() {
-		this.getForm().setValues({
-			label: this.element.configuration.label.value,
-			layout: this.element.configuration.layout
-		});
-	},
-
-	/**
-	 * Get the fields for the element
-	 *
-	 * Based on the TSconfig general allowed fields
-	 * and the TSconfig allowed fields for this type of element
-	 *
-	 * @returns object
-	 */
-	getFieldsBySettings: function() {
-		var fields = [];
-		var elementType = this.element.xtype.split('-').pop();
-
-		var allowedGeneralFields = [];
-		try {
-			allowedGeneralFields = TYPO3.Form.Wizard.Settings.defaults.tabs.options.accordions.label.showProperties.split(/[, ]+/);
-		} catch (error) {
-			// The object has not been found or constructed wrong
-			allowedGeneralFields = [
-				'label',
-				'layout'
-			];
-		}
-
-		var allowedElementFields = [];
-		try {
-			allowedElementFields = TYPO3.Form.Wizard.Settings.elements[elementType].accordions.label.showProperties.split(/[, ]+/);
-		} catch (error) {
-			// The object has not been found or constructed wrong
-			allowedElementFields = allowedGeneralFields;
-		}
-
-		Ext.iterate(allowedElementFields, function(item, index, allItems) {
-			if (allowedGeneralFields.indexOf(item) > -1) {
-				fields.push(item);
-			}
-		}, this);
-
-		return fields;
-	},
-
-	/**
-	 * Called by the clientvalidation event
-	 *
-	 * Adds or removes the error class if the form is valid or not
-	 *
-	 * @param {Object} formPanel This formpanel
-	 * @param {Boolean} valid True if the client validation is true
-	 */
-	validation: function(formPanel, valid) {
-		if (this.el) {
-			if (valid && this.el.hasClass('validation-error')) {
-				this.removeClass('validation-error');
-				this.fireEvent('validation', 'label', valid);
-			} else if (!valid && !this.el.hasClass('validation-error')) {
-				this.addClass('validation-error');
-				this.fireEvent('validation', 'label', valid);
-			}
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-label', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Label);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Legend.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Legend.js
deleted file mode 100644
index 701e7bb793eebd4c519b9801058c6dc1e812bc2b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Legend.js
+++ /dev/null
@@ -1,152 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms');
-
-/**
- * The legend properties of the element
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Legend
- * @extends Ext.FormPanel
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Legend = Ext.extend(Ext.ux.form.FakeFormPanel, {
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('options_legend'),
-
-	/** @cfg {String} defaultType
-	 *
-	 * The default xtype of child Components to create in this Container when
-	 * a child item is specified as a raw configuration object,
-	 * rather than as an instantiated Component.
-	 *
-	 * Defaults to 'panel', except Ext.menu.Menu which defaults to 'menuitem',
-	 * and Ext.Toolbar and Ext.ButtonGroup which default to 'button'.
-	 */
-	defaultType: 'textfield',
-
-	/**
-	 * @cfg {Boolean} monitorValid If true, the form monitors its valid state client-side and
-	 * regularly fires the clientvalidation event passing that state.
-	 * When monitoring valid state, the FormPanel enables/disables any of its configured
-	 * buttons which have been configured with formBind: true depending
-	 * on whether the form is valid or not. Defaults to false
-	 */
-	monitorValid: true,
-
-	/**
-	 * @cfg {String} cls
-	 * An optional extra CSS class that will be added to this component's
-	 * Element (defaults to ''). This can be useful for adding customized styles
-	 * to the component or any of its children using standard CSS rules.
-	 */
-	cls: 'x-panel-accordion',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the form elements to the accordion
-	 */
-	initComponent: function() {
-			// Adds the specified events to the list of events which this Observable may fire.
-		this.addEvents({
-			'validation': true
-		});
-
-		var config = {
-			items: [{
-				xtype: 'fieldset',
-				title: '',
-				autoHeight: true,
-				border: false,
-				defaults: {
-					width: 150,
-					msgTarget: 'side'
-				},
-				defaultType: 'textfieldsubmit',
-				items: [
-					{
-						fieldLabel: TYPO3.l10n.localize('legend_legend'),
-						name: 'legend',
-						enableKeyEvents: true,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					}
-				]
-			}]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Legend.superclass.initComponent.apply(this, arguments);
-
-			// Initialize clientvalidation event
-		this.on('clientvalidation', this.validation, this);
-
-			// Fill the form with the configuration values
-		this.fillForm();
-	},
-
-	/**
-	 * Store a changed value from the form in the element
-	 *
-	 * @param {Object} field The field which has changed
-	 */
-	storeValue: function(field) {
-		if (field.isValid()) {
-			var fieldName = field.getName();
-
-			if (fieldName == 'legend') {
-				var formConfiguration = {
-					legend: {
-						value: field.getValue()
-					}
-				};
-			} else {
-				var formConfiguration = {};
-				formConfiguration[fieldName] = field.getValue();
-			}
-			this.element.setConfigurationValue(formConfiguration);
-		}
-	},
-
-	/**
-	 * Fill the form with the configuration of the element
-	 *
-	 * @param record The current question
-	 * @return void
-	 */
-	fillForm: function() {
-		this.getForm().setValues({
-			legend: this.element.configuration.legend.value
-		});
-	},
-
-	/**
-	 * Called by the clientvalidation event
-	 *
-	 * Adds or removes the error class if the form is valid or not
-	 *
-	 * @param {Object} formPanel This formpanel
-	 * @param {Boolean} valid True if the client validation is true
-	 */
-	validation: function(formPanel, valid) {
-		if (this.el) {
-			if (valid && this.el.hasClass('validation-error')) {
-				this.removeClass('validation-error');
-				this.fireEvent('validation', 'legend', valid);
-			} else if (!valid && !this.el.hasClass('validation-error')) {
-				this.addClass('validation-error');
-				this.fireEvent('validation', 'legend', valid);
-			}
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-legend', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Legend);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Options.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Options.js
deleted file mode 100644
index a4772e7176462e1b750814ec783ddf2142e256a3..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Options.js
+++ /dev/null
@@ -1,249 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms');
-
-/**
- * The options properties of the element
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Options
- * @extends Ext.FormPanel
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Options = Ext.extend(Ext.grid.EditorGridPanel, {
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('options_fieldoptions'),
-
-	/**
-	 * @cfg {String} autoExpandColumn
-	 * The id of a column in this grid that should expand to fill unused space.
-	 * This value specified here can not be 0.
-	 */
-	autoExpandColumn: 'text',
-
-	/**
-	 * @cfg {Number/String} padding
-	 * A shortcut for setting a padding style on the body element. The value can
-	 * either be a number to be applied to all sides, or a normal css string
-	 * describing padding.
-	 */
-	padding: '10px 0 10px 15px',
-
-	/**
-	 * @cfg {Number} clicksToEdit
-	 * The number of clicks on a cell required to display the cell's editor (defaults to 2).
-	 * Setting this option to 'auto' means that mousedown on the selected cell starts
-	 * editing that cell.
-	 */
-	clicksToEdit: 1,
-
-	/**
-	 * @cfg {Object} viewConfig A config object that will be applied to the grid's UI view.  Any of
-	 * the config options available for Ext.grid.GridView can be specified here. This option
-	 * is ignored if view is specified.
-	 */
-	viewConfig: {
-		forceFit: true,
-		emptyText: TYPO3.l10n.localize('fieldoptions_emptytext'),
-		scrollOffset: 0
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Configure store and columns for the grid
-	 */
-	initComponent: function () {
-		var optionRecord = Ext.data.Record.create([
-			{
-				name: 'text',
-				mapping: 'text',
-				type: 'string'
-			}, {
-				name: 'selected',
-				convert: this.convertSelected,
-				type: 'bool'
-			}, {
-				name: 'value',
-				convert: this.convertValue,
-				type: 'string'
-			}
-		]);
-
-		var store = new Ext.data.JsonStore({
-			idIndex: 1,
-			fields: optionRecord,
-			data: this.element.configuration.options,
-			autoDestroy: true,
-			autoSave: true,
-			listeners: {
-				'add': {
-					scope: this,
-					fn: this.storeOptions
-				},
-				'remove': {
-					scope: this,
-					fn: this.storeOptions
-				},
-				'update': {
-					scope: this,
-					fn: this.storeOptions
-				}
-			}
-		});
-
-		var checkColumn = new Ext.ux.grid.SingleSelectCheckColumn({
-			id: 'selected',
-			header: TYPO3.l10n.localize('fieldoptions_selected'),
-			dataIndex: 'selected',
-			width: 20
-		});
-
-		var itemDeleter = new Ext.ux.grid.ItemDeleter();
-
-		var config = {
-			store: store,
-			cm: new Ext.grid.ColumnModel({
-				defaults: {
-					sortable: false
-				},
-				columns: [
-					{
-						width: 40,
-						id: 'data',
-						header: TYPO3.l10n.localize('fieldoptions_text'),
-						dataIndex: 'text',
-						editor: new Ext.ux.form.TextFieldSubmit({
-							allowBlank: false,
-							listeners: {
-								'triggerclick': function (field) {
-									field.gridEditor.record.set('text', field.getValue());
-								}
-							}
-						})
-					},
-					checkColumn,
-					{
-						width: 40,
-						id: 'value',
-						header: TYPO3.l10n.localize('fieldoptions_value'),
-						dataIndex: 'value',
-						editor: new Ext.ux.form.TextFieldSubmit({
-							allowBlank: true,
-							listeners: {
-								'triggerclick': function (field) {
-									field.gridEditor.record.set('value', field.getValue());
-								}
-							}
-						})
-					},
-					itemDeleter
-				]
-			}),
-			selModel: itemDeleter,
-			plugins: [checkColumn],
-			tbar: [{
-				text: TYPO3.l10n.localize('fieldoptions_button_add'),
-				handler: this.addOption,
-				scope: this
-			}]
-		};
-
-		// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-		// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Options.superclass.initComponent.apply(this, arguments);
-	},
-
-	/**
-	 * Adds a new record to the grid
-	 *
-	 * Called when the button to add option in the top bar has been clicked
-	 */
-	addOption: function () {
-		var option = this.store.recordType;
-		var newOption = new option({
-			text: TYPO3.l10n.localize('fieldoptions_new'),
-			selected: false,
-			value: TYPO3.l10n.localize('fieldoptions_value')
-		});
-		this.stopEditing();
-		this.store.add(newOption);
-		this.startEditing(0, 0);
-	},
-
-	/**
-	 * Stores the options in the element whenever a change has been done to the
-	 * grid, like add, remove or update
-	 *
-	 * @param store
-	 * @param record
-	 */
-	storeOptions: function (store, record) {
-		if (record && record.dirty) {
-			record.commit();
-		} else {
-			var option = {};
-			var options = [];
-			this.store.each(function (record) {
-				var option = {
-					text: record.get('text')
-				};
-				if (record.get('selected')) {
-					if (!option.attributes) {
-						option.attributes = {};
-					}
-					option.attributes['selected'] = 'selected';
-				}
-				if (record.get('value')) {
-					if (!option.attributes) {
-						option.attributes = {};
-					}
-					option.attributes['value'] = record.get('value');
-				}
-				options.push(option);
-			});
-			this.element.configuration.options = [];
-			var formConfiguration = {
-				options: options
-			};
-			this.element.setConfigurationValue(formConfiguration);
-		}
-	},
-
-	/**
-	 * Convert and remap the "selected" attribute. In HTML the attribute needs
-	 * be as selected="selected", while the grid uses a boolean.
-	 *
-	 * @param v
-	 * @param record
-	 * @returns {Boolean}
-	 */
-	convertSelected: function (v, record) {
-		if (record.attributes && record.attributes.selected) {
-			if (record.attributes.selected == 'selected') {
-				return true;
-			}
-		}
-		return false;
-	},
-
-	/**
-	 * Remap value from different locations
-	 *
-	 * @param v
-	 * @param record
-	 * @returns {string}
-	 */
-	convertValue: function (v, record) {
-		if (record.attributes && record.attributes.value) {
-			return record.attributes.value;
-		} else if (record.data) {
-			return record.data;
-		}
-		return '';
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-options', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Options);
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation.js
deleted file mode 100644
index 11618cfc04b99009cd170afea1280c89ae60849d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation.js
+++ /dev/null
@@ -1,275 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms');
-
-/**
- * The validation accordion panel in the element options in the left tabpanel
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation
- * @extends Ext.Panel
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation = Ext.extend(Ext.Panel, {
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('options_validation'),
-
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'formwizard-left-options-validation',
-
-	/**
-	 * @cfg {Object} validRules
-	 * Keeps track which rules are valid. Rules contain forms which
-	 * do client validation. If there is a validation change in a form in the
-	 * rule, a validation event will be fired, which changes one of these
-	 * values
-	 */
-	validRules: {
-		alphabetic: true,
-		alphanumeric: true,
-		between: true,
-		date: true,
-		digit: true,
-		email: true,
-		equals: true,
-		fileallowedtypes: true,
-		float: true,
-		greaterthan: true,
-		inarray: true,
-		integer: true,
-		ip: true,
-		length: true,
-		lessthan: true,
-		regexp: true,
-		required: true,
-		uri: true
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the form elements to the accordion
-	 */
-	initComponent: function() {
-		var rules = this.getRulesBySettings();
-
-			// Adds the specified events to the list of events which this Observable may fire.
-		this.addEvents({
-			'validation': true
-		});
-
-		var config = {
-			items: [{
-				xtype: 'typo3-form-wizard-viewport-left-options-forms-validation-dummy',
-				ref: 'dummy'
-			}],
-			tbar: [
-				{
-					xtype: 'combo',
-					hideLabel: true,
-					name: 'rules',
-					ref: 'rules',
-					mode: 'local',
-					triggerAction: 'all',
-					forceSelection: true,
-					editable: false,
-					hiddenName: 'rules',
-					emptyText: TYPO3.l10n.localize('validation_emptytext'),
-					width: 150,
-					displayField: 'label',
-					valueField: 'value',
-					store: new Ext.data.JsonStore({
-						fields: ['label', 'value'],
-						data: rules
-					}),
-					listeners: {
-						'select': {
-							scope: this,
-							fn: this.addRule
-						}
-					}
-				}
-			]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.superclass.initComponent.apply(this, arguments);
-
-			// Initialize the rules when they are available for this element
-		this.initRules();
-	},
-
-	/**
-	 * Called when constructing the validation accordion
-	 *
-	 * Checks if the element already has rules and loads these instead of the dummy
-	 */
-	initRules: function() {
-		var rules = this.element.configuration.validation;
-		if (!Ext.isEmptyObject(rules)) {
-			this.remove(this.dummy);
-			Ext.iterate(rules, function(key, value) {
-				var xtype = 'typo3-form-wizard-viewport-left-options-forms-validation-' + key;
-				if (Ext.ComponentMgr.isRegistered(xtype)) {
-					this.add({
-						xtype: xtype,
-						element: this.element,
-						configuration: value,
-						listeners: {
-							'validation': {
-								fn: this.validation,
-								scope: this
-							}
-						}
-					});
-				}
-			}, this);
-		}
-	},
-
-	/**
-	 * Add a rule to the validation list
-	 *
-	 * @param comboBox
-	 * @param record
-	 * @param index
-	 */
-	addRule: function(comboBox, record, index) {
-		var rule = comboBox.getValue();
-		var xtype = 'typo3-form-wizard-viewport-left-options-forms-validation-' + rule;
-
-		if (!Ext.isEmpty(this.findByType(xtype))) {
-			Ext.MessageBox.alert(TYPO3.l10n.localize('validation_alert_title'), TYPO3.l10n.localize('validation_alert_description'));
-		} else {
-			this.remove(this.dummy);
-
-			this.add({
-				xtype: xtype,
-				element: this.element,
-				listeners: {
-					'validation': {
-						fn: this.validation,
-						scope: this
-					}
-				}
-			});
-			this.doLayout();
-		}
-	},
-
-	/**
-	 * Remove a rule from the validation list
-	 *
-	 * Shows dummy when there is no validation rule for this element
-	 *
-	 * @param component
-	 */
-	removeRule: function(component) {
-		this.remove(component);
-		this.validation(component.rule, true);
-		if (this.items.length == 0) {
-			this.add({
-				xtype: 'typo3-form-wizard-viewport-left-options-forms-validation-dummy',
-				ref: 'dummy'
-			});
-		}
-		this.doLayout();
-	},
-
-	/**
-	 * Get the rules by the TSconfig settings
-	 *
-	 * @returns {Array}
-	 */
-	getRulesBySettings: function() {
-		var rules = [];
-		var elementType = this.element.xtype.split('-').pop();
-
-		var allowedDefaultRules = [];
-		try {
-			allowedDefaultRules = TYPO3.Form.Wizard.Settings.defaults.tabs.options.accordions.validation.showRules.split(/[, ]+/);
-		} catch (error) {
-			// The object has not been found
-			allowedDefaultRules = [
-				'alphabetic',
-				'alphanumeric',
-				'between',
-				'date',
-				'digit',
-				'email',
-				'equals',
-				'fileallowedtypes',
-				'float',
-				'greaterthan',
-				'inarray',
-				'integer',
-				'ip',
-				'length',
-				'lessthan',
-				'regexp',
-				'required',
-				'uri'
-			];
-		}
-
-		var allowedElementRules = [];
-		try {
-			allowedElementRules = TYPO3.Form.Wizard.Settings.elements[elementType].accordions.validation.showRules.split(/[, ]+/);
-		} catch (error) {
-			// The object has not been found or constructed wrong
-			allowedElementRules = allowedDefaultRules;
-		}
-
-		Ext.iterate(allowedElementRules, function(item, index, allItems) {
-			if (allowedDefaultRules.indexOf(item) > -1) {
-				rules.push({label: TYPO3.l10n.localize('validation_' + item), value: item});
-			}
-		}, this);
-
-		return rules;
-	},
-
-	/**
-	 * Called by the validation listeners of the rules
-	 *
-	 * Checks if all rules are valid. If not, adds a class to the accordion
-	 *
-	 * @param {String} rule The rule which fires the event
-	 * @param {Boolean} isValid Rule is valid or not
-	 */
-	validation: function(rule, isValid) {
-		this.validRules[rule] = isValid;
-		var accordionIsValid = true;
-		Ext.iterate(this.validRules, function(key, value) {
-			if (!value) {
-				accordionIsValid = false;
-			}
-		}, this);
-		if (this.el) {
-			if (accordionIsValid && this.el.hasClass('validation-error')) {
-				this.removeClass('validation-error');
-				this.fireEvent('validation', 'validation', isValid);
-			} else if (!accordionIsValid && !this.el.hasClass('validation-error')) {
-				this.addClass('validation-error');
-				this.fireEvent('validation', 'validation', isValid);
-			}
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Alphabetic.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Alphabetic.js
deleted file mode 100644
index eb9fd1a5f5076f8b710c4a5330c828050bc6a245..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Alphabetic.js
+++ /dev/null
@@ -1,36 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The alphabetic validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Alphabetic
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Alphabetic = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'alphabetic',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_alphabetic.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_alphabetic.error'),
-				allowWhiteSpace: 0
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Alphabetic.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-alphabetic', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Alphabetic);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Alphanumeric.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Alphanumeric.js
deleted file mode 100644
index bbd4cdf0f1f8fc6733a19c4fb7a1aa6b7373a67a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Alphanumeric.js
+++ /dev/null
@@ -1,36 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The alphanumeric validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Alphanumeric
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Alphanumeric = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'alphanumeric',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_alphanumeric.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_alphanumeric.error'),
-				allowWhiteSpace: 0
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Alphanumeric.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-alphanumeric', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Alphanumeric);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Between.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Between.js
deleted file mode 100644
index bb45fc96b04a5d4458cd81dae843336227f55a0c..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Between.js
+++ /dev/null
@@ -1,38 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The between validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Between
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Between = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'between',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_between.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_between.error'),
-				minimum: 0,
-				maximum: 0,
-				inclusive: 0
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Between.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-between', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Between);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Date.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Date.js
deleted file mode 100644
index ac222c02fb1cc1ae8c8d72ec2e724efe3a87d62d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Date.js
+++ /dev/null
@@ -1,36 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The date validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Date
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Date = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'date',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_date.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_date.error'),
-				format: '%e-%m-%Y'
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Date.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-date', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Date);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Digit.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Digit.js
deleted file mode 100644
index 501dafd326ab84dbf439e3b2b7a27f032300cf99..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Digit.js
+++ /dev/null
@@ -1,35 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The digit validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Digit
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Digit = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'digit',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_digit.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_digit.error')
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Digit.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-digit', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Digit);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Dummy.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Dummy.js
deleted file mode 100644
index 603b73edfa39ae5aba64df07eca317efd3673b65..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Dummy.js
+++ /dev/null
@@ -1,58 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The dummy item when no validation rule is defined for an element
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Dummy
- * @extends Ext.Panel
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Dummy = Ext.extend(Ext.Panel, {
-	/**
-	 * @cfg {Boolean} border
-	 * True to display the borders of the panel's body element, false to hide
-	 * them (defaults to true). By default, the border is a 2px wide inset
-	 * border, but this can be further altered by setting bodyBorder to false.
-	 */
-	border: false,
-
-	/**
-	 * @cfg {Number/String} padding
-	 * A shortcut for setting a padding style on the body element. The value can
-	 * either be a number to be applied to all sides, or a normal css string
-	 * describing padding.
-	 */
-	padding: 0,
-
-	/**
-	 * @cfg {String} cls
-	 * An optional extra CSS class that will be added to this component's
-	 * Element (defaults to ''). This can be useful for adding customized styles
-	 * to the component or any of its children using standard CSS rules.
-	 */
-	cls: 'formwizard-left-dummy typo3-message message-information',
-
-	/**
-	 * @cfg {Mixed} data
-	 * The initial set of data to apply to the tpl to update the content area of
-	 * the Component.
-	 */
-	data: [{
-		title: TYPO3.l10n.localize('validation_dummy_title'),
-		description: TYPO3.l10n.localize('validation_dummy_description')
-	}],
-
-	/**
-	 * @cfg {Mixed} tpl
-	 * An Ext.Template, Ext.XTemplate or an array of strings to form an
-	 * Ext.XTemplate. Used in conjunction with the data and tplWriteMode
-	 * configurations.
-	 */
-	tpl: new Ext.XTemplate(
-		'<tpl for=".">',
-			'<p><strong>{title}</strong></p>',
-			'<p>{description}</p>',
-		'</tpl>'
-	)
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-dummy', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Dummy);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Email.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Email.js
deleted file mode 100644
index 391e7725d44538bb83e0842a83d0c993cd02193a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Email.js
+++ /dev/null
@@ -1,35 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The email validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Email
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Email = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'email',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_email.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_email.error')
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Email.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-email', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Email);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Equals.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Equals.js
deleted file mode 100644
index f80f8c1385e3007240ec2010c998036e437fc17f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Equals.js
+++ /dev/null
@@ -1,36 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The equals validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Email
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Equals = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'equals',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_equals.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_equals.error'),
-				field: ''
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Equals.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-equals', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Equals);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/FileAllowedTypes.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/FileAllowedTypes.js
deleted file mode 100644
index ba7baa124e7347c0d69af3f43ee578fe0ce7e7db..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/FileAllowedTypes.js
+++ /dev/null
@@ -1,36 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.FileAllowedTypes');
-
-/**
- * The allowed file types rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileAllowedTypes
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileAllowedTypes = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'fileallowedtypes',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_fileallowedtypes.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_fileallowedtypes.error'),
-				types: ''
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileAllowedTypes.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-fileallowedtypes', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileAllowedTypes);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/FileMaximumSize.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/FileMaximumSize.js
deleted file mode 100644
index 967e7226895ce7c06c0d95ae9dad70e41f343ea1..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/FileMaximumSize.js
+++ /dev/null
@@ -1,36 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.FileMaximumSize');
-
-/**
- * The maximum file size rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileMaximumSize
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileMaximumSize = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'filemaximumsize',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_filemaximumsize.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_filemaximumsize.error'),
-				maximum: 0
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileMaximumSize.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-filemaximumsize', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileMaximumSize);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/FileMinimumSize.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/FileMinimumSize.js
deleted file mode 100644
index 5304191023b4ad1fe2ea38bd8d3f0136cf4e6031..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/FileMinimumSize.js
+++ /dev/null
@@ -1,36 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.FileMinimumSize');
-
-/**
- * The minimum file size rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileMinimumSize
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileMinimumSize = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'fileminimumsize',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_fileminimumsize.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_fileminimumsize.error'),
-				minimum: 0
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileMinimumSize.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-fileminimumsize', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.FileMinimumSize);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Float.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Float.js
deleted file mode 100644
index e189f462b8b894db12f614acb725fae80acd5b3f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Float.js
+++ /dev/null
@@ -1,35 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The float validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Float
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Float = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'float',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_float.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_float.error')
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Float.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-float', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Float);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/GreaterThan.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/GreaterThan.js
deleted file mode 100644
index 795a460c40d03794c483c33ce620af5da199eabd..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/GreaterThan.js
+++ /dev/null
@@ -1,36 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The greater than validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.GreaterThan
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.GreaterThan = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'greaterthan',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_greaterthan.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_greaterthan.error'),
-				minimum: 0
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.GreaterThan.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-greaterthan', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.GreaterThan);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/InArray.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/InArray.js
deleted file mode 100644
index 0f922089db455eabc5bfe302c0c5a57ff86b4c96..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/InArray.js
+++ /dev/null
@@ -1,37 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The in arrayt validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.InArray
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.InArray = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'inarray',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_inarray.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_inarray.error'),
-				array: '',
-				strict: 0
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.InArray.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-inarray', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.InArray);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Integer.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Integer.js
deleted file mode 100644
index 5219315f26e2197634a8b0e01f474cae4dd0116d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Integer.js
+++ /dev/null
@@ -1,35 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The integer validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Integer
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Integer = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'integer',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_integer.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_integer.error')
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Integer.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-integer', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Integer);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Ip.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Ip.js
deleted file mode 100644
index 7e65761eb46ff738d73b52f527dfff7ad22f0d55..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Ip.js
+++ /dev/null
@@ -1,35 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The IP validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Ip
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Ip = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'ip',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_ip.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_ip.error')
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Ip.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-ip', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Ip);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Length.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Length.js
deleted file mode 100644
index 7ba06c3ee70cf30d373945602954239bae4be8b6..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Length.js
+++ /dev/null
@@ -1,37 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The length validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Length
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Length = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'length',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_length.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_length.error'),
-				minimum: 0,
-				maximum: 0
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Length.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-length', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Length);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/LessThan.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/LessThan.js
deleted file mode 100644
index a3db3b6bc155f57540c1b5f3e49eedb369f0122e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/LessThan.js
+++ /dev/null
@@ -1,36 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The less than validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.LessThan
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.LessThan = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'lessthan',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_lessthan.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_lessthan.error'),
-				maximum: 0
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.LessThan.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-lessthan', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.LessThan);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/RegExp.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/RegExp.js
deleted file mode 100644
index 059eda36154ecf439c3b5e956a8fb9ab9733ac4c..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/RegExp.js
+++ /dev/null
@@ -1,36 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The regular expression validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.RegExp
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.RegExp = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'regexp',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_regexp.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_regexp.error'),
-				expression: ''
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.RegExp.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-regexp', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.RegExp);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Required.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Required.js
deleted file mode 100644
index f15fe85c28008b24d2915900e9e01b6eac2090f8..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Required.js
+++ /dev/null
@@ -1,35 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The required validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Required
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Required = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'required',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_required.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_required.error')
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Required.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-required', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Required);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Rule.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Rule.js
deleted file mode 100644
index 7dfc5d061f2180de230d7797740e785101b06e98..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Rule.js
+++ /dev/null
@@ -1,436 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The validation rules abstract
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- * @extends Ext.FormPanel
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule = Ext.extend(Ext.ux.form.FakeFormPanel, {
-	/**
-	 * @cfg {Boolean} border
-	 * True to display the borders of the panel's body element, false to hide
-	 * them (defaults to true). By default, the border is a 2px wide inset
-	 * border, but this can be further altered by setting bodyBorder to false.
-	 */
-	border: false,
-
-	/**
-	 * @cfg {Number/String} padding
-	 * A shortcut for setting a padding style on the body element. The value can
-	 * either be a number to be applied to all sides, or a normal css string
-	 * describing padding.
-	 */
-	padding: 0,
-
-	/**
-	 * @cfg {String} defaultType
-	 *
-	 * The default xtype of child Components to create in this Container when
-	 * a child item is specified as a raw configuration object,
-	 * rather than as an instantiated Component.
-	 *
-	 * Defaults to 'panel', except Ext.menu.Menu which defaults to 'menuitem',
-	 * and Ext.Toolbar and Ext.ButtonGroup which default to 'button'.
-	 */
-	defaultType: 'textfield',
-
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: '',
-
-	/**
-	 * @cfg {Boolean} monitorValid If true, the form monitors its valid state client-side and
-	 * regularly fires the clientvalidation event passing that state.
-	 * When monitoring valid state, the FormPanel enables/disables any of its configured
-	 * buttons which have been configured with formBind: true depending
-	 * on whether the form is valid or not. Defaults to false
-	 */
-	monitorValid: true,
-
-	/**
-	 * Constructor
-	 */
-	initComponent: function() {
-		var fields = this.getFieldsBySettings();
-		var formItems = new Array();
-
-			// Adds the specified events to the list of events which this Observable may fire.
-		this.addEvents({
-			'validation': true
-		});
-
-		Ext.iterate(fields, function(item, index, allItems) {
-			switch(item) {
-				case 'message':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('validation_properties_message'),
-						name: 'message',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'error':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('validation_properties_error'),
-						name: 'error',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'showMessage':
-					formItems.push({
-						xtype: 'checkbox',
-						fieldLabel: TYPO3.l10n.localize('validation_properties_showmessage'),
-						name: 'showMessage',
-						inputValue: '1',
-						listeners: {
-							'check': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'allowWhiteSpace':
-					formItems.push({
-						xtype: 'checkbox',
-						fieldLabel: TYPO3.l10n.localize('validation_properties_allowwhitespace'),
-						name: 'allowWhiteSpace',
-						inputValue: '1',
-						listeners: {
-							'check': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'minimum':
-					formItems.push({
-						xtype: 'spinnerfield',
-						fieldLabel: TYPO3.l10n.localize('validation_properties_minimum'),
-						name: 'minimum',
-						minValue: 0,
-						accelerate: true,
-						listeners: {
-							'spin': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'maximum':
-					formItems.push({
-						xtype: 'spinnerfield',
-						fieldLabel: TYPO3.l10n.localize('validation_properties_maximum'),
-						name: 'maximum',
-						minValue: 0,
-						accelerate: true,
-						listeners: {
-							'spin': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'inclusive':
-					formItems.push({
-						xtype: 'checkbox',
-						fieldLabel: TYPO3.l10n.localize('validation_properties_inclusive'),
-						name: 'inclusive',
-						inputValue: '1',
-						listeners: {
-							'check': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'format':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('validation_properties_format'),
-						name: 'format',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'field':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('validation_properties_field'),
-						name: 'field',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'array':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('validation_properties_array'),
-						name: 'array',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'expression':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('validation_properties_expression'),
-						name: 'expression',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-				case 'types':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('validation_properties_types'),
-						name: 'types',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-			}
-		}, this);
-
-		formItems.push({
-			xtype: 'button',
-			text: TYPO3.l10n.localize('button_remove'),
-			handler: this.removeRule,
-			scope: this
-		});
-
-		var config = {
-			items: [
-				{
-					xtype: 'fieldset',
-					title: TYPO3.l10n.localize('validation_' + this.rule),
-					autoHeight: true,
-					defaults: {
-						width: 128,
-						msgTarget: 'side'
-					},
-					defaultType: 'textfieldsubmit',
-					items: formItems
-				}
-			]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule.superclass.initComponent.apply(this, arguments);
-
-			// Initialize clientvalidation event
-		this.on('clientvalidation', this.validation, this);
-
-			// Strange, but we need to call doLayout() after render
-		this.on('afterrender', this.newOrExistingRule, this);
-	},
-
-	/**
-	 * Decide whether this is a new or an existing one
-	 *
-	 * If new, the default configuration has to be added to the validation rules
-	 * of the element, otherwise we can fill the form with the existing configuration
-	 */
-	newOrExistingRule: function() {
-		this.doLayout();
-			// Existing rule
-		if (this.element.configuration.validation[this.rule]) {
-			this.fillForm();
-			// New rule
-		} else {
-			this.addRuleToElement();
-		}
-	},
-
-	/**
-	 * Fill the form with the configuration of the element
-	 *
-	 * When filling, the events of all form elements should be suspended,
-	 * otherwise the values are written back to the element, for instance on a
-	 * check event on a checkbox.
-	 */
-	fillForm: function() {
-		this.suspendEventsBeforeFilling();
-		this.getForm().setValues(this.element.configuration.validation[this.rule]);
-		this.resumeEventsAfterFilling();
-	},
-
-	/**
-	 * Suspend the events on all items within this component
-	 */
-	suspendEventsBeforeFilling: function() {
-		this.cascade(function(item) {
-			item.suspendEvents();
-		});
-	},
-
-	/**
-	 * Resume the events on all items within this component
-	 */
-	resumeEventsAfterFilling: function() {
-		this.cascade(function(item) {
-			item.resumeEvents();
-		});
-	},
-
-	/**
-	 * Add this rule to the element
-	 */
-	addRuleToElement: function() {
-		var formConfiguration = {validation: {}};
-		formConfiguration.validation[this.rule] = this.configuration;
-
-		this.element.setConfigurationValue(formConfiguration);
-
-		this.fillForm();
-	},
-
-	/**
-	 * Store a changed value from the form in the element
-	 *
-	 * @param {Object} field The field which has changed
-	 */
-	storeValue: function(field) {
-		if (field.isValid()) {
-			var fieldName = field.getName();
-
-			var formConfiguration = {validation: {}};
-			formConfiguration.validation[this.rule] = {};
-			formConfiguration.validation[this.rule][fieldName] = field.getValue();
-
-			this.element.setConfigurationValue(formConfiguration);
-		}
-	},
-
-	/**
-	 * Remove the rule
-	 *
-	 * Called when the remove button of this rule has been clicked
-	 */
-	removeRule: function() {
-		this.ownerCt.removeRule(this);
-		this.element.removeValidationRule(this.rule);
-	},
-
-	/**
-	 * Get the fields for the element
-	 *
-	 * Based on the TSconfig general allowed fields
-	 * and the TSconfig allowed fields for this type of element
-	 *
-	 * @returns object
-	 */
-	getFieldsBySettings: function() {
-		var fields = [];
-		var ruleFields = this.configuration;
-		var elementType = this.element.xtype.split('-').pop();
-
-		var allowedGeneralFields = [];
-		try {
-			allowedGeneralFields = TYPO3.Form.Wizard.Settings.defaults.tabs.options.accordions.validation.rules[this.rule].showProperties.split(/[, ]+/);
-		} catch (error) {
-			// The object has not been found or constructed wrong
-			allowedGeneralFields = [
-				'message',
-				'error',
-				'showMessage',
-				'allowWhiteSpace',
-				'minimum',
-				'maximum',
-				'inclusive',
-				'format',
-				'field',
-				'array',
-				'strict',
-				'expression'
-			];
-		}
-
-		var allowedElementFields = [];
-		try {
-			allowedElementFields = TYPO3.Form.Wizard.Settings.elements[elementType].accordions.validation.rules[this.rule].showProperties.split(/[, ]+/);
-		} catch (error) {
-			// The object has not been found or constructed wrong
-			allowedElementFields = allowedGeneralFields;
-		}
-
-		Ext.iterate(allowedElementFields, function(item, index, allItems) {
-			if (allowedGeneralFields.indexOf(item) > -1 && Ext.isDefined(ruleFields[item])) {
-				fields.push(item);
-			}
-		}, this);
-
-		return fields;
-	},
-
-	/**
-	 * Called by the clientvalidation event
-	 *
-	 * Adds or removes the error class if the form is valid or not
-	 *
-	 * @param {Object} formPanel This formpanel
-	 * @param {Boolean} valid True if the client validation is true
-	 */
-	validation: function(formPanel, valid) {
-		if (this.el) {
-			if (valid && this.el.hasClass('validation-error')) {
-				this.removeClass('validation-error');
-				this.fireEvent('validation', this.rule, valid);
-			} else if (!valid && !this.el.hasClass('validation-error')) {
-				this.addClass('validation-error');
-				this.fireEvent('validation', this.rule, valid);
-			}
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-rule', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Uri.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Uri.js
deleted file mode 100644
index 5503a70b9acfae0629952dfaa1be6cf02090b060..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Validation/Uri.js
+++ /dev/null
@@ -1,35 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation');
-
-/**
- * The uri validation rule
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Uri
- * @extends TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Uri = Ext.extend(TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Rule, {
-	/**
-	 * @cfg {String} rule
-	 *
-	 * The name of this rule
-	 */
-	rule: 'uri',
-
-	/**
-	 * Constructor
-	 *
-	 * Add the configuration object to this component
-	 * @param config
-	 */
-	constructor: function(config) {
-		Ext.apply(this, {
-			configuration: {
-				showMessage: 1,
-				message: TYPO3.l10n.localize('tx_form_system_validate_uri.message'),
-				error: TYPO3.l10n.localize('tx_form_system_validate_uri.error')
-			}
-		});
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Uri.superclass.constructor.apply(this, arguments);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-validation-uri', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Validation.Uri);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Various.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Various.js
deleted file mode 100644
index 499fa4e8566dfda73db13c3578819d8f46397471..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Forms/Various.js
+++ /dev/null
@@ -1,290 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options.Forms');
-
-/**
- * The various properties of the element
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Various
- * @extends Ext.FormPanel
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Various = Ext.extend(Ext.ux.form.FakeFormPanel, {
-	/**
-	 * @cfg {String} title
-	 * The title text to be used as innerHTML (html tags are accepted) to
-	 * display in the panel header (defaults to '').
-	 */
-	title: TYPO3.l10n.localize('options_various'),
-
-	/** @cfg {String} defaultType
-	 *
-	 * The default xtype of child Components to create in this Container when
-	 * a child item is specified as a raw configuration object,
-	 * rather than as an instantiated Component.
-	 *
-	 * Defaults to 'panel', except Ext.menu.Menu which defaults to 'menuitem',
-	 * and Ext.Toolbar and Ext.ButtonGroup which default to 'button'.
-	 */
-	defaultType: 'textfield',
-
-	/**
-	 * @cfg {Boolean} monitorValid If true, the form monitors its valid state client-side and
-	 * regularly fires the clientvalidation event passing that state.
-	 * When monitoring valid state, the FormPanel enables/disables any of its configured
-	 * buttons which have been configured with formBind: true depending
-	 * on whether the form is valid or not. Defaults to false
-	 */
-	monitorValid: true,
-
-	/**
-	 * Constructor
-	 *
-	 * Add the form elements to the accordion
-	 */
-	initComponent: function() {
-		var various = this.element.configuration.various;
-		var formItems = new Array();
-
-			// Adds the specified events to the list of events which this Observable may fire.
-		this.addEvents({
-			'validation': true
-		});
-
-		Ext.iterate(various, function(key, value) {
-			switch(key) {
-				case 'name':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('various_properties_name'),
-						name: 'name',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'content':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('various_properties_content'),
-						xtype: 'textarea',
-						name: 'content',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'text':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('various_properties_text'),
-						xtype: 'textarea',
-						name: 'text',
-						allowBlank: false,
-						listeners: {
-							'triggerclick': {
-								scope: this,
-								fn: this.storeValue
-							},
-							'blur': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'headingSize':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('various_properties_headingsize'),
-						name: 'headingSize',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'headingSize',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: 'H1', value: 'h1'},
-								{label: 'H2', value: 'h2'},
-								{label: 'H3', value: 'h3'},
-								{label: 'H4', value: 'h4'},
-								{label: 'H5', value: 'h5'}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'prefix':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('various_properties_prefix'),
-						name: 'prefix',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'prefix',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('yes'), value: true},
-								{label: TYPO3.l10n.localize('no'), value: false}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'suffix':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('various_properties_suffix'),
-						name: 'suffix',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'suffix',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('yes'), value: true},
-								{label: TYPO3.l10n.localize('no'), value: false}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-				case 'middleName':
-					formItems.push({
-						fieldLabel: TYPO3.l10n.localize('various_properties_middlename'),
-						name: 'middleName',
-						xtype: 'combo',
-						mode: 'local',
-						triggerAction: 'all',
-						forceSelection: true,
-						editable: false,
-						hiddenName: 'middleName',
-						displayField: 'label',
-						valueField: 'value',
-						store: new Ext.data.JsonStore({
-							fields: ['label', 'value'],
-							data: [
-								{label: TYPO3.l10n.localize('yes'), value: true},
-								{label: TYPO3.l10n.localize('no'), value: false}
-							]
-						}),
-						listeners: {
-							'select': {
-								scope: this,
-								fn: this.storeValue
-							}
-						}
-					});
-					break;
-			}
-		}, this);
-
-		var config = {
-			items: [{
-				xtype: 'fieldset',
-				title: '',
-				autoHeight: true,
-				border: false,
-				defaults: {
-					width: 150,
-					msgTarget: 'side'
-				},
-				defaultType: 'textfieldsubmit',
-				items: formItems
-			}]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Various.superclass.initComponent.apply(this, arguments);
-
-			// Initialize clientvalidation event
-		this.on('clientvalidation', this.validation, this);
-
-			// Fill the form with the configuration values
-		this.fillForm();
-	},
-
-	/**
-	 * Store a changed value from the form in the element
-	 *
-	 * @param {Object} field The field which has changed
-	 */
-	storeValue: function(field) {
-		if (field.isValid()) {
-			var fieldName = field.getName();
-
-			var formConfiguration = {various: {}};
-			formConfiguration.various[fieldName] = field.getValue();
-
-			this.element.setConfigurationValue(formConfiguration);
-		}
-	},
-
-	/**
-	 * Fill the form with the configuration of the element
-	 *
-	 * @return void
-	 */
-	fillForm: function() {
-		this.getForm().setValues(this.element.configuration.various);
-	},
-
-	/**
-	 * Called by the clientvalidation event
-	 *
-	 * Adds or removes the error class if the form is valid or not
-	 *
-	 * @param {Object} formPanel This formpanel
-	 * @param {Boolean} valid True if the client validation is true
-	 */
-	validation: function(formPanel, valid) {
-		if (this.el) {
-			if (valid && this.el.hasClass('validation-error')) {
-				this.removeClass('validation-error');
-				this.fireEvent('validation', 'various', valid);
-			} else if (!valid && !this.el.hasClass('validation-error')) {
-				this.addClass('validation-error');
-				this.fireEvent('validation', 'various', valid);
-			}
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-forms-various', TYPO3.Form.Wizard.Viewport.Left.Options.Forms.Various);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Panel.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Panel.js
deleted file mode 100644
index acff06a5a3d0eaf12b76239bbc6724d4b92a77ac..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Left/Options/Panel.js
+++ /dev/null
@@ -1,148 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport.Left.Options');
-
-/**
- * The options panel
- *
- * @class TYPO3.Form.Wizard.Viewport.Left.Options.Panel
- * @extends Ext.Panel
- */
-TYPO3.Form.Wizard.Viewport.Left.Options.Panel = Ext.extend(Ext.Panel, {
-	/**
-	 * @cfg {Object} element
-	 * The element for the options form
-	 */
-	element: null,
-
-	/**
-	 * @cfg {Boolean} border
-	 * True to display the borders of the panel's body element, false to hide
-	 * them (defaults to true). By default, the border is a 2px wide inset
-	 * border, but this can be further altered by setting bodyBorder to false.
-	 */
-	border: false,
-
-	/**
-	 * @cfg {Object|Function} defaults
-	 * This option is a means of applying default settings to all added items
-	 * whether added through the items config or via the add or insert methods.
-	 */
-	defaults: {
-		autoHeight: true,
-		border: false,
-		padding: 0
-	},
-
-	/**
-	 * Constructor
-	 *
-	 * Add the form elements to the tab
-	 */
-	initComponent: function() {
-		var accordions = this.getAccordionsBySettings();
-		var accordionItems = new Array();
-
-		// Adds the specified events to the list of events which this Observable may fire.
-		this.addEvents({
-			'validation': true
-		});
-
-		Ext.iterate(accordions, function(item, index, allItems) {
-			var accordionXtype = 'typo3-form-wizard-viewport-left-options-forms-' + item;
-			accordionItems.push({
-				xtype: accordionXtype,
-				element: this.element,
-				listeners: {
-					'validation': {
-						fn: this.validation,
-						scope: this
-					}
-				}
-			});
-		}, this);
-
-		var config = {
-			items: [{
-				xtype: 'panel',
-				layout: 'accordion',
-				ref: 'accordion',
-				defaults: {
-					autoHeight: true,
-					cls: 'x-panel-accordion'
-				},
-				items: accordionItems
-			}]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Left.Options.Panel.superclass.initComponent.apply(this, arguments);
-	},
-
-	/**
-	 * Adds the accordions depending on the TSconfig settings
-	 *
-	 * It will first look at showAccordions for the tab, then it will filter it
-	 * down with the accordions allowed for the element.
-	 *
-	 * @returns {Array}
-	 */
-	getAccordionsBySettings: function() {
-		var accordions = [];
-		if (this.element) {
-			var elementType = this.element.xtype.split('-').pop();
-
-			var allowedDefaultAccordions = [];
-			try {
-				allowedDefaultAccordions = TYPO3.Form.Wizard.Settings.defaults.tabs.options.showAccordions.split(/[, ]+/);
-			} catch (error) {
-				// The object has not been found
-				allowedDefaultAccordions = [
-					'legend',
-					'label',
-					'attributes',
-					'options',
-					'validation',
-					'filters',
-					'various'
-				];
-			}
-
-			var allowedElementAccordions = [];
-			try {
-				allowedElementAccordions = TYPO3.Form.Wizard.Settings.elements[elementType].showAccordions.split(/[, ]+/);
-			} catch (error) {
-				// The object has not been found
-				allowedElementAccordions = allowedDefaultAccordions;
-			}
-
-			Ext.iterate(allowedElementAccordions, function(item, index, allItems) {
-				var accordionXtype = 'typo3-form-wizard-viewport-left-options-forms-' + item;
-				if (
-					Ext.isDefined(this.element.configuration[item]) &&
-					allowedElementAccordions.indexOf(item) > -1 &&
-					Ext.ComponentMgr.isRegistered(accordionXtype)
-				) {
-					accordions.push(item);
-				}
-			}, this);
-		}
-
-		return accordions;
-	},
-
-	/**
-	 * Fire the validation event
-	 *
-	 * This is only a pass-through for the accordion validation events
-	 *
-	 * @param accordion
-	 * @param valid
-	 */
-	validation: function(accordion, valid) {
-		this.fireEvent('validation', accordion, valid);
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-left-options-panel', TYPO3.Form.Wizard.Viewport.Left.Options.Panel);
\ No newline at end of file
diff --git a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Right.js b/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Right.js
deleted file mode 100644
index 994fee3aec4c36f0905f7ad6f87a45b45bc5ef2d..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Resources/Public/JavaScript/Wizard/Viewport/Right.js
+++ /dev/null
@@ -1,144 +0,0 @@
-Ext.namespace('TYPO3.Form.Wizard.Viewport');
-
-/**
- * The form container on the right side
- *
- * @class TYPO3.Form.Wizard.Viewport.Right
- * @extends TYPO3.Form.Wizard.Elements.Container
- */
-TYPO3.Form.Wizard.Viewport.Right = Ext.extend(Ext.Container, {
-	/**
-	 * @cfg {String} id
-	 * The unique id of this component (defaults to an auto-assigned id).
-	 * You should assign an id if you need to be able to access the component
-	 * later and you do not have an object reference available
-	 * (e.g., using Ext.getCmp).
-	 *
-	 * Note that this id will also be used as the element id for the containing
-	 * HTML element that is rendered to the page for this component.
-	 * This allows you to write id-based CSS rules to style the specific
-	 * instance of this component uniquely, and also to select sub-elements
-	 * using this component's id as the parent.
-	 */
-	id: 'formwizard-right',
-
-	/**
-	 * @cfg {Mixed} autoEl
-	 * A tag name or DomHelper spec used to create the Element which will
-	 * encapsulate this Component.
-	 */
-	autoEl: 'ol',
-
-	/**
-	 * @cfg {String} region
-	 * Note: this config is only used when this BoxComponent is rendered
-	 * by a Container which has been configured to use the BorderLayout
-	 * layout manager (e.g. specifying layout:'border').
-	 */
-	region: 'center',
-
-	/**
-	 * @cfg {Boolean} autoScroll
-	 * true to use overflow:'auto' on the components layout element and show
-	 * scroll bars automatically when necessary, false to clip any overflowing
-	 * content (defaults to false).
-	 */
-	autoScroll: true,
-
-	/**
-	 * Constructor
-	 */
-	initComponent: function() {
-		var config = {
-			items: [
-				{
-					xtype: 'typo3-form-wizard-elements-basic-form'
-				}
-			]
-		};
-
-			// apply config
-		Ext.apply(this, Ext.apply(this.initialConfig, config));
-
-			// call parent
-		TYPO3.Form.Wizard.Viewport.Right.superclass.initComponent.apply(this, arguments);
-
-			// Initialize the form after rendering
-		this.on('afterrender', this.initializeForm, this);
-	},
-
-	/**
-	 * Initialize the form after rendering
-	 */
-	initializeForm: function() {
-		this.loadForm();
-
-	},
-
-	/**
-	 * Load the form from config
-	 *
-	 * Loads the configuration and initializes the history
-	 */
-	loadForm: function() {
-		this.loadConfiguration(TYPO3.Form.Wizard.Settings.Configuration);
-		this.initializeHistory();
-	},
-
-	/**
-	 * Initialize the history
-	 *
-	 * After the form has been rendered for the first time, we need to add the
-	 * initial configuration to the history, so it is possible to go back to the
-	 * initial state of the form when it was loaded.
-	 */
-	initializeHistory: function() {
-		TYPO3.Form.Wizard.Helpers.History.setHistory();
-		this.setForm();
-	},
-
-	/**
-	 * Called by the history class when a change has been made in the form
-	 *
-	 * Constructs an array out of this component and the children to add it to
-	 * the history or to use when saving the form
-	 *
-	 * @returns {Array}
-	 */
-	getConfiguration: function() {
-		var historyConfiguration = new Array;
-
-		if (this.items) {
-			this.items.each(function(item, index, length) {
-				historyConfiguration.push(item.getConfiguration());
-			}, this);
-		}
-		return historyConfiguration;
-	},
-
-	/**
-	 * Load a previous configuration from the history
-	 *
-	 * Removes all the components from this container and adds the components
-	 * from the history configuration depending on the 'undo' or 'redo' action.
-	 *
-	 * @param historyConfiguration
-	 */
-	loadConfiguration: function(historyConfiguration) {
-		this.removeAll();
-		this.add(historyConfiguration);
-		this.doLayout();
-		this.setForm();
-	},
-
-	/**
-	 * Pass the form configuration to the left form tab
-	 */
-	setForm: function() {
-		if (Ext.getCmp('formwizard-left-form')) {
-			Ext.getCmp('formwizard-left-form').setForm(this.get(0));
-		}
-	}
-});
-
-Ext.reg('typo3-form-wizard-viewport-right', TYPO3.Form.Wizard.Viewport.Right);
diff --git a/typo3/sysext/form/Tests/Unit/Controller/AbstractBackendControllerTest.php b/typo3/sysext/form/Tests/Unit/Controller/AbstractBackendControllerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ddbf506ca1712bb04358b12f53ac51472834c89c
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Controller/AbstractBackendControllerTest.php
@@ -0,0 +1,48 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Controller;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Form\Controller\AbstractBackendController;
+
+/**
+ * Test case
+ */
+class AbstractBackendControllerTest extends UnitTestCase
+{
+
+    /**
+     * @test
+     */
+    public function resolveResourcePathsExpectResolve()
+    {
+        $mockController = $this->getAccessibleMockForAbstractClass(
+            AbstractBackendController::class,
+            [],
+            '',
+            false
+        );
+
+        $input = [
+            0 => 'EXT:form/Resources/Public/Css/form.css'
+        ];
+
+        $expected = [
+            0 => 'typo3/sysext/form/Resources/Public/Css/form.css'
+        ];
+
+        $this->assertSame($expected, $mockController->_call('resolveResourcePaths', $input));
+    }
+}
diff --git a/typo3/sysext/form/Tests/Unit/Controller/Fixtures/BackendUtilityFixture.php b/typo3/sysext/form/Tests/Unit/Controller/Fixtures/BackendUtilityFixture.php
new file mode 100644
index 0000000000000000000000000000000000000000..45177c90790b930036b4da6a51e5005ef94e664f
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Controller/Fixtures/BackendUtilityFixture.php
@@ -0,0 +1,60 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Tests\Unit\Controller\Fixtures;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Fixture for BackendUtility methods
+ */
+class BackendUtilityFixture
+{
+
+    /**
+     * @param string $table
+     * @param int $uid
+     * @param string $fields
+     * @param string $where
+     * @param bool $useDeleteClause
+     * @return array
+     */
+    public static function getRecord($table, $uid, $fields = '*', $where = '', $useDeleteClause = true)
+    {
+        return [
+            'uid' => 1,
+        ];
+    }
+
+    /**
+     * @param string $table
+     * @param array $row
+     * @param bool $prep
+     * @param bool $forceResult
+     * @return string
+     */
+    public static function getRecordTitle($table, $row, $prep = false, $forceResult = true)
+    {
+        return 'record title';
+    }
+
+    /**
+     * @param string $moduleName
+     * @param array $urlParameters
+     * @return string
+     */
+    public static function getModuleUrl($moduleName, $urlParameters = [])
+    {
+        return '/typo3/index.php?some=param';
+    }
+}
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Button.html b/typo3/sysext/form/Tests/Unit/Controller/Fixtures/BlankForm.yaml
similarity index 100%
rename from typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Button.html
rename to typo3/sysext/form/Tests/Unit/Controller/Fixtures/BlankForm.yaml
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/ButtonTag.html b/typo3/sysext/form/Tests/Unit/Controller/Fixtures/SimpleContactForm.yaml
similarity index 100%
rename from typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/ButtonTag.html
rename to typo3/sysext/form/Tests/Unit/Controller/Fixtures/SimpleContactForm.yaml
diff --git a/typo3/sysext/form/Tests/Unit/Controller/FormEditorControllerTest.php b/typo3/sysext/form/Tests/Unit/Controller/FormEditorControllerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..92a7e48d9c21d7949ce40cbb48446ec86d4faa6d
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Controller/FormEditorControllerTest.php
@@ -0,0 +1,424 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Controller;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Form\Controller\FormEditorController;
+use TYPO3\CMS\Form\Domain\Exception\RenderingException;
+use TYPO3\CMS\Form\Service\TranslationService;
+
+/**
+ * Test case
+ */
+class FormEditorControllerTest extends UnitTestCase
+{
+
+    /**
+     * @var array A backup of registered singleton instances
+     */
+    protected $singletonInstances = [];
+
+    /**
+     * Set up
+     */
+    public function setUp()
+    {
+        $this->singletonInstances = GeneralUtility::getSingletonInstances();
+    }
+
+    /**
+     * Tear down
+     */
+    public function tearDown()
+    {
+        GeneralUtility::resetSingletonInstances($this->singletonInstances);
+        parent::tearDown();
+    }
+
+    /**
+     * @test
+     */
+    public function getInsertRenderablesPanelConfigurationReturnsGroupedAndSortedConfiguration()
+    {
+        $mockController = $this->getAccessibleMock(FormEditorController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $objectMangerProphecy = $this->prophesize(ObjectManager::class);
+        GeneralUtility::setSingletonInstance(ObjectManager::class, $objectMangerProphecy->reveal());
+
+        $mockTranslationService = $this->getAccessibleMock(TranslationService::class, [
+            'translate'
+        ], [], '', false);
+
+        $mockTranslationService
+            ->expects($this->any())
+            ->method('translate')
+            ->willReturnArgument(4);
+
+        $objectMangerProphecy
+            ->get(TranslationService::class)
+            ->willReturn($mockTranslationService);
+
+        $mockController->_set('prototypeConfiguration', [
+            'formEditor' => [
+                'formElementGroups' => [
+                    'input' => [
+                        'label' => 'Basic elements',
+                    ],
+                    'select' => [
+                        'label' => 'Select elements',
+                    ],
+                ],
+            ],
+        ]);
+
+        $input = [
+            'Password' => [
+                'group' => 'input',
+                'groupSorting' => 110,
+                'iconIdentifier' => 't3-form-icon-password',
+                'label' => 'Password label',
+            ],
+            'Text' => [
+                'group' => 'input',
+                'groupSorting' => 100,
+                'iconIdentifier' => 't3-form-icon-text',
+                'label' => 'Text label',
+            ],
+            'SingleSelect' => [
+                'group' => 'select',
+                'groupSorting' => 100,
+                'iconIdentifier' => 't3-form-icon-single-select',
+                'label' => 'Single select label',
+            ],
+        ];
+
+        $expected = [
+            0 => [
+                'key' => 'input',
+                'elements' => [
+                    0 => [
+                        'key' => 'Text',
+                        'cssKey' => 'text',
+                        'label' => 'Text label',
+                        'sorting' => 100,
+                        'iconIdentifier' => 't3-form-icon-text',
+                    ],
+                    1 => [
+                        'key' => 'Password',
+                        'cssKey' => 'password',
+                        'label' => 'Password label',
+                        'sorting' => 110,
+                        'iconIdentifier' => 't3-form-icon-password',
+                    ],
+                ],
+                'label' => 'Basic elements',
+            ],
+            1 => [
+                'key' => 'select',
+                'elements' => [
+                    0 => [
+                        'key' => 'SingleSelect',
+                        'cssKey' => 'singleselect',
+                        'label' => 'Single select label',
+                        'sorting' => 100,
+                        'iconIdentifier' => 't3-form-icon-single-select',
+                    ],
+                ],
+                'label' => 'Select elements',
+            ],
+        ];
+
+        $this->assertSame($expected, $mockController->_call('getInsertRenderablesPanelConfiguration', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function getFormEditorDefinitionsReturnReducedConfiguration()
+    {
+        $mockController = $this->getAccessibleMock(FormEditorController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $objectMangerProphecy = $this->prophesize(ObjectManager::class);
+        GeneralUtility::setSingletonInstance(ObjectManager::class, $objectMangerProphecy->reveal());
+
+        $mockTranslationService = $this->getAccessibleMock(TranslationService::class, [
+            'translateValuesRecursive'
+        ], [], '', false);
+
+        $mockTranslationService
+            ->expects($this->any())
+            ->method('translateValuesRecursive')
+            ->willReturnArgument(0);
+
+        $objectMangerProphecy
+            ->get(TranslationService::class)
+            ->willReturn($mockTranslationService);
+
+        $mockController->_set('prototypeConfiguration', [
+            'formEditor' => [
+                'someOtherValues' => [
+                    'horst' => [
+                        'key' => 'value',
+                    ],
+                    'gertrud' => [
+                        'key' => 'value',
+                    ],
+                ],
+                'formElementPropertyValidatorsDefinition' => [
+                    'NotEmpty' => [
+                        'key' => 'value',
+                    ],
+                ],
+            ],
+            'formElementsDefinition' => [
+                'Form' => [
+                    'formEditor' => [
+                        'key' => 'value',
+                    ],
+                    'someOtherValues' => [
+                        'horst' => [
+                            'key' => 'value',
+                        ],
+                        'gertrud' => [
+                            'key' => 'value',
+                        ],
+                    ],
+                ],
+                'Text' => [
+                    'formEditor' => [
+                        'key' => 'value',
+                    ],
+                    'someOtherValues' => [
+                        'horst' => [
+                            'key' => 'value',
+                        ],
+                        'gertrud' => [
+                            'key' => 'value',
+                        ],
+                    ],
+                ],
+            ],
+            'finishersDefinition' => [
+                'Confirmation' => [
+                    'formEditor' => [
+                        'key' => 'value',
+                    ],
+                    'someOtherValues' => [
+                        'horst' => [
+                            'key' => 'value',
+                        ],
+                        'gertrud' => [
+                            'key' => 'value',
+                        ],
+                    ],
+                ],
+                'EmailToSender' => [
+                    'formEditor' => [
+                        'key' => 'value',
+                    ],
+                    'someOtherValues' => [
+                        'horst' => [
+                            'key' => 'value',
+                        ],
+                        'gertrud' => [
+                            'key' => 'value',
+                        ],
+                    ],
+                ],
+            ],
+            'someOtherValues' => [
+                'horst' => [
+                    'key' => 'value',
+                ],
+                'gertrud' => [
+                    'key' => 'value',
+                ],
+            ],
+        ]);
+
+        $expected = [
+            'formElements' => [
+                'Form' => [
+                    'key' => 'value',
+                ],
+                'Text' => [
+                    'key' => 'value',
+                ],
+            ],
+            'finishers' => [
+                'Confirmation' => [
+                    'key' => 'value',
+                ],
+                'EmailToSender' => [
+                    'key' => 'value',
+                ],
+            ],
+            'formElementPropertyValidators' => [
+                'NotEmpty' => [
+                    'key' => 'value',
+                ],
+            ],
+        ];
+
+        $this->assertSame($expected, $mockController->_call('getFormEditorDefinitions'));
+    }
+
+    /**
+     * @test
+     */
+    public function convertJsonArrayToAssociativeArrayReturnTransformedArray()
+    {
+        $mockController = $this->getAccessibleMock(FormEditorController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $input = [
+            'francine' => 'stan',
+            'properties' => [
+                'options' => [
+                    0 => [
+                        '_label' => 'label',
+                        '_value' => 'value',
+                    ],
+                ],
+            ],
+        ];
+
+        $expected = [
+            'francine' => 'stan',
+            'properties' => [
+                'options' => [
+                    'value' => 'label',
+                ],
+            ],
+        ];
+
+        $this->assertSame($expected, $mockController->_call('convertJsonArrayToAssociativeArray', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function renderFormEditorTemplatesThrowsExceptionIfTemplateRootPathsNotSet()
+    {
+        $this->expectException(RenderingException::class);
+        $this->expectExceptionCode(1480294720);
+
+        $mockController = $this->getAccessibleMock(FormEditorController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $mockController->_call('renderFormEditorTemplates', [], []);
+    }
+
+    /**
+     * @test
+     */
+    public function renderFormEditorTemplatesThrowsExceptionIfTemplateRootPathsNotArray()
+    {
+        $this->expectException(RenderingException::class);
+        $this->expectExceptionCode(1480294720);
+
+        $mockController = $this->getAccessibleMock(FormEditorController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $input = [
+            'templateRootPaths' => '',
+        ];
+        $mockController->_call('renderFormEditorTemplates', $input, []);
+    }
+
+    /**
+     * @test
+     */
+    public function renderFormEditorTemplatesThrowsExceptionIfLayoutRootPathsNotSet()
+    {
+        $this->expectException(RenderingException::class);
+        $this->expectExceptionCode(1480294721);
+
+        $mockController = $this->getAccessibleMock(FormEditorController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $input = [
+            'templateRootPaths' => [],
+        ];
+        $mockController->_call('renderFormEditorTemplates', $input, []);
+    }
+
+    /**
+     * @test
+     */
+    public function renderFormEditorTemplatesThrowsExceptionIfLayoutRootPathsNotArray()
+    {
+        $this->expectException(RenderingException::class);
+        $this->expectExceptionCode(1480294721);
+
+        $mockController = $this->getAccessibleMock(FormEditorController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $input = [
+            'templateRootPaths' => [],
+            'layoutRootPaths' => '',
+        ];
+        $mockController->_call('renderFormEditorTemplates', $input, []);
+    }
+
+    /**
+     * @test
+     */
+    public function renderFormEditorTemplatesThrowsExceptionIfPartialRootPathsNotSet()
+    {
+        $this->expectException(RenderingException::class);
+        $this->expectExceptionCode(1480294722);
+
+        $mockController = $this->getAccessibleMock(FormEditorController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $input = [
+            'templateRootPaths' => [],
+            'layoutRootPaths' => [],
+        ];
+        $mockController->_call('renderFormEditorTemplates', $input, []);
+    }
+
+    /**
+     * @test
+     */
+    public function renderFormEditorTemplatesThrowsExceptionIfPartialRootPathsNotArray()
+    {
+        $this->expectException(RenderingException::class);
+        $this->expectExceptionCode(1480294722);
+
+        $mockController = $this->getAccessibleMock(FormEditorController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $input = [
+            'templateRootPaths' => [],
+            'layoutRootPaths' => [],
+        ];
+        $mockController->_call('renderFormEditorTemplates', $input, []);
+    }
+}
diff --git a/typo3/sysext/form/Tests/Unit/Controller/FormFrontendControllerTest.php b/typo3/sysext/form/Tests/Unit/Controller/FormFrontendControllerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..8c79fddb7a15bbc2e6bbcd19cc679d0a780c2294
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Controller/FormFrontendControllerTest.php
@@ -0,0 +1,418 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Controller;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Prophecy\Argument;
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Form\Controller\FormFrontendController;
+use TYPO3\CMS\Form\Domain\Configuration\ConfigurationService;
+use TYPO3\CMS\Form\Mvc\Configuration\TypoScriptService;
+
+/**
+ * Test case
+ */
+class FormFrontendControllerTest extends UnitTestCase
+{
+
+    /**
+     * @test
+     */
+    public function overrideByFlexFormSettingsReturnsNoOverriddenConfigurationIfFlexformOverridesDisabled()
+    {
+        $mockController = $this->getAccessibleMock(FormFrontendController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $configurationServiceProphecy = $this->prophesize(ConfigurationService::class);
+
+        $objectManagerMock = $this->createMock(ObjectManager::class);
+        $objectManagerMock
+            ->expects($this->any())
+            ->method('get')
+            ->with(ConfigurationService::class)
+            ->willReturn($configurationServiceProphecy->reveal());
+
+        $mockController->_set('objectManager', $objectManagerMock);
+
+        $configurationServiceProphecy->getPrototypeConfiguration(Argument::cetera())->willReturn([
+            'finishersDefinition' => [
+                'EmailToReceiver' => [
+                    'FormEngine' => [
+                        'elements' => [
+                            'subject' => [],
+                            'recipientAddress' => [],
+                            'format' => [],
+                        ],
+                    ],
+                ],
+            ],
+        ]);
+
+        $mockController->_set('settings', [
+            'overrideFinishers' => 0,
+            'finishers' => [
+                'EmailToReceiver' => [
+                    'subject' => 'Mesage Subject overridden',
+                    'recipientAddress' => 'your.company@example.com overridden',
+                    'format' => 'html overridden',
+                ],
+            ],
+        ]);
+
+        $input = [
+            'identifier' => 'ext-form-identifier',
+            'prototypeName' => 'standard',
+            'finishers' => [
+                0 => [
+                    'identifier' => 'EmailToReceiver',
+                    'options' => [
+                        'subject' => 'Mesage Subject',
+                        'recipientAddress' => 'your.company@example.com',
+                        'format' => 'html',
+                    ],
+                ],
+            ],
+        ];
+
+        $expected = [
+            'identifier' => 'ext-form-identifier',
+            'prototypeName' => 'standard',
+            'finishers' => [
+                0 => [
+                    'identifier' => 'EmailToReceiver',
+                    'options' => [
+                        'subject' => 'Mesage Subject',
+                        'recipientAddress' => 'your.company@example.com',
+                        'format' => 'html',
+                    ],
+                ],
+            ],
+        ];
+
+        $this->assertSame($expected, $mockController->_call('overrideByFlexFormSettings', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function overrideByFlexFormSettingsReturnsOverriddenConfigurationIfFlexformOverridesEnabled()
+    {
+        $mockController = $this->getAccessibleMock(FormFrontendController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $configurationServiceProphecy = $this->prophesize(ConfigurationService::class);
+
+        $objectManagerMock = $this->createMock(ObjectManager::class);
+        $objectManagerMock
+            ->expects($this->any())
+            ->method('get')
+            ->with(ConfigurationService::class)
+            ->willReturn($configurationServiceProphecy->reveal());
+
+        $mockController->_set('objectManager', $objectManagerMock);
+
+        $configurationServiceProphecy->getPrototypeConfiguration(Argument::cetera())->willReturn([
+            'finishersDefinition' => [
+                'EmailToReceiver' => [
+                    'FormEngine' => [
+                        'elements' => [
+                            'subject' => [],
+                            'recipientAddress' => [],
+                            'format' => [],
+                        ],
+                    ],
+                ],
+            ],
+        ]);
+
+        $mockController->_set('settings', [
+            'overrideFinishers' => 1,
+            'finishers' => [
+                'EmailToReceiver' => [
+                    'subject' => 'Mesage Subject overridden',
+                    'recipientAddress' => 'your.company@example.com overridden',
+                    'format' => 'html overridden',
+                ],
+            ],
+        ]);
+
+        $input = [
+            'identifier' => 'ext-form-identifier',
+            'prototypeName' => 'standard',
+            'finishers' => [
+                0 => [
+                    'identifier' => 'EmailToReceiver',
+                    'options' => [
+                        'subject' => 'Mesage Subject',
+                        'recipientAddress' => 'your.company@example.com',
+                        'format' => 'html',
+                    ],
+                ],
+            ],
+        ];
+
+        $expected = [
+            'identifier' => 'ext-form-identifier',
+            'prototypeName' => 'standard',
+            'finishers' => [
+                0 => [
+                    'identifier' => 'EmailToReceiver',
+                    'options' => [
+                        'subject' => 'Mesage Subject overridden',
+                        'recipientAddress' => 'your.company@example.com overridden',
+                        'format' => 'html overridden',
+                    ],
+                ],
+            ],
+        ];
+
+        $this->assertSame($expected, $mockController->_call('overrideByFlexFormSettings', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function overrideByFlexFormSettingsReturnsNotOverriddenConfigurationKeyIfFlexformOverridesAreNotRepresentedInFormEngineConfiguration()
+    {
+        $mockController = $this->getAccessibleMock(FormFrontendController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $configurationServiceProphecy = $this->prophesize(ConfigurationService::class);
+
+        $objectManagerMock = $this->createMock(ObjectManager::class);
+        $objectManagerMock
+            ->expects($this->any())
+            ->method('get')
+            ->with(ConfigurationService::class)
+            ->willReturn($configurationServiceProphecy->reveal());
+
+        $mockController->_set('objectManager', $objectManagerMock);
+
+        $configurationServiceProphecy->getPrototypeConfiguration(Argument::cetera())->willReturn([
+            'finishersDefinition' => [
+                'EmailToReceiver' => [
+                    'FormEngine' => [
+                        'elements' => [
+                            'subject' => [],
+                            'recipientAddress' => [],
+                        ],
+                    ],
+                ],
+            ],
+        ]);
+
+        $mockController->_set('settings', [
+            'overrideFinishers' => 1,
+            'finishers' => [
+                'EmailToReceiver' => [
+                    'subject' => 'Mesage Subject overridden',
+                    'recipientAddress' => 'your.company@example.com overridden',
+                    'format' => 'html overridden',
+                ],
+            ],
+        ]);
+
+        $input = [
+            'identifier' => 'ext-form-identifier',
+            'prototypeName' => 'standard',
+            'finishers' => [
+                0 => [
+                    'identifier' => 'EmailToReceiver',
+                    'options' => [
+                        'subject' => 'Mesage Subject',
+                        'recipientAddress' => 'your.company@example.com',
+                        'format' => 'html',
+                    ],
+                ],
+            ],
+        ];
+
+        $expected = [
+            'identifier' => 'ext-form-identifier',
+            'prototypeName' => 'standard',
+            'finishers' => [
+                0 => [
+                    'identifier' => 'EmailToReceiver',
+                    'options' => [
+                        'subject' => 'Mesage Subject overridden',
+                        'recipientAddress' => 'your.company@example.com overridden',
+                        'format' => 'html',
+                    ],
+                ],
+            ],
+        ];
+
+        $this->assertSame($expected, $mockController->_call('overrideByFlexFormSettings', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function overrideByTypoScriptSettingsReturnsNotOverriddenConfigurationIfNoTypoScriptOverridesExists()
+    {
+        $mockController = $this->getAccessibleMock(FormFrontendController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $typoScriptServiceProphecy = $this->prophesize(TypoScriptService::class);
+
+        $objectManagerMock = $this->createMock(ObjectManager::class);
+        $objectManagerMock
+            ->expects($this->any())
+            ->method('get')
+            ->with(TypoScriptService::class)
+            ->willReturn($typoScriptServiceProphecy->reveal());
+
+        $mockController->_set('objectManager', $objectManagerMock);
+
+        $typoScriptServiceProphecy
+            ->resolvePossibleTypoScriptConfiguration(Argument::cetera())
+            ->willReturnArgument(0);
+
+        $mockController->_set('settings', [
+            'formDefinitionOverrides' => [
+            ],
+        ]);
+
+        $input = [
+            'identifier' => 'ext-form-identifier',
+            'prototypeName' => 'standard',
+            'label' => 'Label',
+            'renderables' => [
+                0 => [
+                    'identifier' => 'page-1',
+                    'type' => 'Page',
+                    'label' => 'Label',
+                    'renderables' => [
+                        0 => [
+                            'identifier' => 'text-1',
+                            'type' => 'Text',
+                            'label' => 'Label',
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $expected = [
+            'identifier' => 'ext-form-identifier',
+            'prototypeName' => 'standard',
+            'label' => 'Label',
+            'renderables' => [
+                0 => [
+                    'identifier' => 'page-1',
+                    'type' => 'Page',
+                    'label' => 'Label',
+                    'renderables' => [
+                        0 => [
+                            'identifier' => 'text-1',
+                            'type' => 'Text',
+                            'label' => 'Label',
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $this->assertSame($expected, $mockController->_call('overrideByTypoScriptSettings', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function overrideByTypoScriptSettingsReturnsOverriddenConfigurationIfTypoScriptOverridesExists()
+    {
+        $mockController = $this->getAccessibleMock(FormFrontendController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $typoScriptServiceProphecy = $this->prophesize(TypoScriptService::class);
+
+        $objectManagerMock = $this->createMock(ObjectManager::class);
+        $objectManagerMock
+            ->expects($this->any())
+            ->method('get')
+            ->with(TypoScriptService::class)
+            ->willReturn($typoScriptServiceProphecy->reveal());
+
+        $mockController->_set('objectManager', $objectManagerMock);
+
+        $typoScriptServiceProphecy
+            ->resolvePossibleTypoScriptConfiguration(Argument::cetera())
+            ->willReturnArgument(0);
+
+        $mockController->_set('settings', [
+            'formDefinitionOverrides' => [
+                'ext-form-identifier' => [
+                    'label' => 'Label override',
+                    'renderables' => [
+                        0 => [
+                            'renderables' => [
+                                0 => [
+                                    'label' => 'Label override',
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ]);
+
+        $input = [
+            'identifier' => 'ext-form-identifier',
+            'prototypeName' => 'standard',
+            'label' => 'Label',
+            'renderables' => [
+                0 => [
+                    'identifier' => 'page-1',
+                    'type' => 'Page',
+                    'label' => 'Label',
+                    'renderables' => [
+                        0 => [
+                            'identifier' => 'text-1',
+                            'type' => 'Text',
+                            'label' => 'Label',
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $expected = [
+            'identifier' => 'ext-form-identifier',
+            'prototypeName' => 'standard',
+            'label' => 'Label override',
+            'renderables' => [
+                0 => [
+                    'identifier' => 'page-1',
+                    'type' => 'Page',
+                    'label' => 'Label',
+                    'renderables' => [
+                        0 => [
+                            'identifier' => 'text-1',
+                            'type' => 'Text',
+                            'label' => 'Label override',
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $this->assertSame($expected, $mockController->_call('overrideByTypoScriptSettings', $input));
+    }
+}
diff --git a/typo3/sysext/form/Tests/Unit/Controller/FormManagerControllerTest.php b/typo3/sysext/form/Tests/Unit/Controller/FormManagerControllerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..83ac02029597a9d4fd64b3a922e43d45f9559da3
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Controller/FormManagerControllerTest.php
@@ -0,0 +1,410 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Controller;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Prophecy\Argument;
+use TYPO3\CMS\Core\Resource\Folder;
+use TYPO3\CMS\Core\Resource\ResourceStorage;
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext;
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Form\Controller\FormManagerController;
+use TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager;
+use TYPO3\CMS\Form\Service\TranslationService;
+use TYPO3\CMS\Form\Tests\Unit\Controller\Fixtures\BackendUtilityFixture;
+
+/**
+ * Test case
+ */
+class FormManagerControllerTest extends UnitTestCase
+{
+
+    /**
+     * @var array A backup of registered singleton instances
+     */
+    protected $singletonInstances = [];
+
+    /**
+     * Set up
+     */
+    public function setUp()
+    {
+        $this->singletonInstances = GeneralUtility::getSingletonInstances();
+    }
+
+    /**
+     * Tear down
+     */
+    public function tearDown()
+    {
+        GeneralUtility::resetSingletonInstances($this->singletonInstances);
+        parent::tearDown();
+    }
+
+    /**
+     * @test
+     */
+    public function getAccessibleFormStorageFoldersReturnsProcessedArray()
+    {
+        $mockController = $this->getAccessibleMock(FormManagerController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $formPersistenceManagerProphecy = $this->prophesize(FormPersistenceManager::class);
+
+        $mockStorage = $this->getMockBuilder(ResourceStorage::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $mockController->_set('formPersistenceManager', $formPersistenceManagerProphecy->reveal());
+
+        $folder1 = new Folder($mockStorage, '/user_upload/', 'user_upload');
+        $folder2 = new Folder($mockStorage, '/forms/', 'forms');
+
+        $formPersistenceManagerProphecy->getAccessibleFormStorageFolders(Argument::cetera())->willReturn([
+            '1:/user_upload/' => $folder1,
+            '2:/forms/' => $folder2,
+        ]);
+
+        $expected = [
+            0 => [
+                'label' => 'user_upload',
+                'value' => '1:/user_upload/',
+            ],
+            1 => [
+                'label' => 'forms',
+                'value' => '2:/forms/',
+            ],
+        ];
+
+        $this->assertSame($expected, $mockController->_call('getAccessibleFormStorageFolders'));
+    }
+
+    /**
+     * @test
+     */
+    public function getFormManagerAppInitialDataReturnsProcessedArray()
+    {
+        $objectMangerProphecy = $this->prophesize(ObjectManager::class);
+        GeneralUtility::setSingletonInstance(ObjectManager::class, $objectMangerProphecy->reveal());
+
+        $mockTranslationService = $this->getAccessibleMock(TranslationService::class, [
+            'translateValuesRecursive'
+        ], [], '', false);
+
+        $mockTranslationService
+            ->expects($this->any())
+            ->method('translateValuesRecursive')
+            ->willReturnArgument(0);
+
+        $objectMangerProphecy
+            ->get(TranslationService::class)
+            ->willReturn($mockTranslationService);
+
+        $mockController = $this->getAccessibleMock(FormManagerController::class, [
+            'getAccessibleFormStorageFolders'
+        ], [], '', false);
+
+        $mockUriBuilder = $this->createMock(UriBuilder::class);
+        $mockControllerContext = $this->createMock(ControllerContext::class);
+        $mockControllerContext
+            ->expects($this->any())
+            ->method('getUriBuilder')
+            ->will($this->returnValue($mockUriBuilder));
+
+        $mockController->_set('controllerContext', $mockControllerContext);
+
+        $mockController->_set('formSettings', [
+            'formManager' => [
+                'selectablePrototypesConfiguration' => [],
+            ],
+        ]);
+
+        $mockUriBuilder->expects($this->any())->method('uriFor')->willReturn(
+            '/typo3/index.php?some=param'
+        );
+
+        $mockController
+            ->expects($this->any())
+            ->method('getAccessibleFormStorageFolders')
+            ->willReturn([
+                0 => [
+                    'label' => 'user_upload',
+                    'value' => '1:/user_upload/',
+                ],
+            ]);
+
+        $expected = [
+            'selectablePrototypesConfiguration' => [],
+            'accessibleFormStorageFolders' => [
+                0 => [
+                    'label' => 'user_upload',
+                    'value' => '1:/user_upload/',
+                ],
+            ],
+            'endpoints' => [
+                'create' => '/typo3/index.php?some=param',
+                'duplicate' => '/typo3/index.php?some=param',
+                'delete' => '/typo3/index.php?some=param',
+                'references' => '/typo3/index.php?some=param',
+            ],
+        ];
+
+        $this->assertSame(json_encode($expected), $mockController->_call('getFormManagerAppInitialData'));
+    }
+
+    /**
+     * @test
+     */
+    public function getAvailableFormDefinitionsReturnsProcessedArray()
+    {
+        $mockController = $this->getAccessibleMock(FormManagerController::class, [
+            'getReferences'
+        ], [], '', false);
+
+        $formPersistenceManagerProphecy = $this->prophesize(FormPersistenceManager::class);
+        $mockController->_set('formPersistenceManager', $formPersistenceManagerProphecy->reveal());
+
+        $formPersistenceManagerProphecy->listForms(Argument::cetera())->willReturn([
+            0 => [
+                'identifier' => 'ext-form-identifier',
+                'name' => 'some name',
+                'persistenceIdentifier' => '1:/user_uploads/someFormName.yaml',
+                'readOnly' => false,
+                'location' => 'storage',
+                'duplicateIdentifier' => false,
+            ],
+        ]);
+
+        $mockController
+            ->expects($this->any())
+            ->method('getReferences')
+            ->willReturn([
+                'someRow',
+                'anotherRow',
+            ]);
+
+        $expected = [
+            0 => [
+                'identifier' => 'ext-form-identifier',
+                'name' => 'some name',
+                'persistenceIdentifier' => '1:/user_uploads/someFormName.yaml',
+                'readOnly' => false,
+                'location' => 'storage',
+                'duplicateIdentifier' => false,
+                'referenceCount' => 2,
+            ],
+        ];
+
+        $this->assertSame($expected, $mockController->_call('getAvailableFormDefinitions'));
+    }
+
+    /**
+     * @test
+     */
+    public function getProcessedReferencesRowsThrowsExceptionIfPersistenceIdentifierIsEmpty()
+    {
+        $this->expectException(\InvalidArgumentException::class);
+        $this->expectExceptionCode(1477071939);
+
+        $mockController = $this->getAccessibleMock(FormManagerController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $mockController->_call('getProcessedReferencesRows', '');
+    }
+
+    /**
+     * @test
+     */
+    public function getProcessedReferencesRowsReturnsProcessedArray()
+    {
+        $mockController = $this->getAccessibleMock(FormManagerController::class, [
+            'getReferences',
+            'getBackendUtility',
+        ], [], '', false);
+
+        $mockController
+            ->expects($this->any())
+            ->method('getBackendUtility')
+            ->willReturn(BackendUtilityFixture::class);
+
+        $mockController
+            ->expects($this->any())
+            ->method('getReferences')
+            ->willReturn([
+                0 => [
+                    'tablename' => 'tt_content',
+                    'recuid' => -1,
+                ],
+            ]);
+
+        $expected = [
+            0 => [
+                'recordPageTitle' => 'record title',
+                'recordTitle' => 'record title',
+                'recordIcon' =>
+'<span class="t3js-icon icon icon-size-small icon-state-default icon-default-not-found" data-identifier="default-not-found">
+	<span class="icon-markup">
+<img src="typo3/sysext/core/Resources/Public/Icons/T3Icons/default/default-not-found.svg" width="16" height="16" />
+	</span>
+	
+</span>',
+                'recordUid' => -1,
+                'recordEditUrl' => '/typo3/index.php?some=param',
+            ],
+        ];
+
+        $this->assertSame($expected, $mockController->_call('getProcessedReferencesRows', 'fake'));
+    }
+
+    /**
+     * @test
+     */
+    public function isValidTemplatePathReturnsTrueIfTemplateIsDefinedAndExists()
+    {
+        $mockController = $this->getAccessibleMock(FormManagerController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $mockController->_set('formSettings', [
+            'formManager' => [
+                'selectablePrototypesConfiguration' => [
+                    0 => [
+                        'identifier' => 'standard',
+                        'label' => 'some label',
+                        'newFormTemplates' => [
+                            0 => [
+                                'templatePath' => 'EXT:form/Tests/Unit/Controller/Fixtures/BlankForm.yaml',
+                                'label' => 'some label',
+                            ],
+                            1 => [
+                                'templatePath' => 'EXT:form/Tests/Unit/Controller/Fixtures/SimpleContactForm.yaml',
+                                'label' => 'some other label',
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ]);
+
+        $this->assertTrue($mockController->_call('isValidTemplatePath', 'standard', 'EXT:form/Tests/Unit/Controller/Fixtures/SimpleContactForm.yaml'));
+    }
+
+    /**
+     * @test
+     */
+    public function isValidTemplatePathReturnsFalseIfTemplateIsDefinedButNotExists()
+    {
+        $mockController = $this->getAccessibleMock(FormManagerController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $mockController->_set('formSettings', [
+            'formManager' => [
+                'selectablePrototypesConfiguration' => [
+                    0 => [
+                        'identifier' => 'standard',
+                        'label' => 'some label',
+                        'newFormTemplates' => [
+                            0 => [
+                                'templatePath' => 'EXT:form/Tests/Unit/Controller/Fixtures/BlankForm.yaml',
+                                'label' => 'some label',
+                            ],
+                            1 => [
+                                'templatePath' => 'EXT:form/Tests/Unit/Controller/Fixtures/SimpleContactForm.yaml',
+                                'label' => 'some other label',
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ]);
+
+        $this->assertFalse($mockController->_call('isValidTemplatePath', 'standard', 'EXT:form/Tests/Unit/Controller/Fixtures/NonExistingForm.yaml'));
+    }
+
+    /**
+     * @test
+     */
+    public function isValidTemplatePathReturnsFalseIfTemplateIsNotDefinedAndExists()
+    {
+        $mockController = $this->getAccessibleMock(FormManagerController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $mockController->_set('formSettings', [
+            'formManager' => [
+                'selectablePrototypesConfiguration' => [
+                    0 => [
+                        'identifier' => 'standard',
+                        'label' => 'some label',
+                        'newFormTemplates' => [
+                            0 => [
+                                'templatePath' => 'EXT:form/Tests/Unit/Controller/Fixtures/BlankForm.yaml',
+                                'label' => 'some label',
+                            ],
+                            1 => [
+                                'templatePath' => 'EXT:form/Tests/Unit/Controller/Fixtures/SimpleContactForm.yaml',
+                                'label' => 'some other label',
+                            ],
+                        ],
+                    ],
+                    1 => [
+                        'identifier' => 'other',
+                        'label' => 'some label',
+                        'newFormTemplates' => [
+                            0 => [
+                                'templatePath' => 'EXT:form/Tests/Unit/Controller/Fixtures/BlankForm.yaml',
+                                'label' => 'some label',
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ]);
+
+        $this->assertFalse($mockController->_call('isValidTemplatePath', 'other', 'EXT:form/Tests/Unit/Controller/Fixtures/SimpleContactForm.yaml'));
+    }
+
+    /**
+     * @test
+     */
+    public function convertFormNameToIdentifierRemoveSpaces()
+    {
+        $mockController = $this->getAccessibleMock(FormManagerController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $input = 'test form';
+        $expected = 'testform';
+        $this->assertSame($expected, $mockController->_call('convertFormNameToIdentifier', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function convertFormNameToIdentifierRemoveSpecialChars()
+    {
+        $mockController = $this->getAccessibleMock(FormManagerController::class, [
+            'dummy'
+        ], [], '', false);
+
+        $input = 'test form ä#!_-01';
+        $expected = 'testform_-01';
+        $this->assertSame($expected, $mockController->_call('convertFormNameToIdentifier', $input));
+    }
+}
diff --git a/typo3/sysext/form/Tests/Unit/Domain/Configuration/ConfigurationServiceTest.php b/typo3/sysext/form/Tests/Unit/Domain/Configuration/ConfigurationServiceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..76a6ab53d8003f0d862ac70a04933187f44670e6
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Domain/Configuration/ConfigurationServiceTest.php
@@ -0,0 +1,71 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Domain\Configuration;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Form\Domain\Configuration\ConfigurationService;
+use TYPO3\CMS\Form\Domain\Configuration\Exception\PrototypeNotFoundException;
+
+/**
+ * Test case
+ */
+class ConfigurationServiceTest extends UnitTestCase
+{
+
+    /**
+     * @test
+     */
+    public function getPrototypeConfigurationReturnsPrototypeConfiguration()
+    {
+        $mockConfigurationService = $this->getAccessibleMock(ConfigurationService::class, [
+            'dummy'
+        ], [], '', false);
+
+        $mockConfigurationService->_set('formSettings', [
+            'prototypes' => [
+                'standard' => [
+                    'key' => 'value',
+                ],
+            ],
+        ]);
+
+        $expected = [
+            'key' => 'value',
+        ];
+
+        $this->assertSame($expected, $mockConfigurationService->getPrototypeConfiguration('standard'));
+    }
+
+    /**
+     * @test
+     */
+    public function getPrototypeConfigurationThrowsExceptionIfNoPrototypeFound()
+    {
+        $mockConfigurationService = $this->getAccessibleMock(ConfigurationService::class, [
+            'dummy'
+        ], [], '', false);
+
+        $this->expectException(PrototypeNotFoundException::class);
+        $this->expectExceptionCode(1475924277);
+
+        $mockConfigurationService->_set('formSettings', [
+            'prototypes' => [
+                'noStandard' => [],
+                ],
+            ]);
+
+        $mockConfigurationService->getPrototypeConfiguration('standard');
+    }
+}
diff --git a/typo3/sysext/form/Tests/Unit/Domain/Model/ConfigurationTest.php b/typo3/sysext/form/Tests/Unit/Domain/Model/ConfigurationTest.php
deleted file mode 100644
index ca41160d961488d119f0cae99cbd03cd4f3569ab..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Domain/Model/ConfigurationTest.php
+++ /dev/null
@@ -1,136 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Domain;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Tests\UnitTestCase;
-use TYPO3\CMS\Form\Domain\Model\Configuration;
-use TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository;
-
-/**
- * Test case for class \TYPO3\CMS\Form\Domain\Model\Configuration
- */
-class ConfigurationTest extends UnitTestCase
-{
-    /**
-     * @var Configuration
-     */
-    protected $subject = null;
-
-    /*
-     * @var TypoScriptRepository|\Prophecy\Prophecy\ObjectProphecy
-     */
-    protected $typoScriptRepositoryProphecy;
-
-    /**
-     * Sets up this test case.
-     */
-    protected function setUp()
-    {
-        parent::setUp();
-        $this->typoScriptRepositoryProphecy = $this->prophesize(TypoScriptRepository::class);
-        $this->subject = $this->getAccessibleMock(Configuration::class, ['__none']);
-        $this->subject->_set('typoScriptRepository', $this->typoScriptRepositoryProphecy->reveal());
-    }
-
-    /**
-     * Tears down this test case.
-     */
-    protected function tearDown()
-    {
-        parent::tearDown();
-        unset($this->typoScriptRepositoryProphecy);
-        unset($this->subject);
-    }
-
-    /**
-     * @param array $typoScript
-     * @param string $globalThemeName
-     * @param array $expected
-     *
-     * @test
-     * @dataProvider propertiesAreUpdatedFromTypoScriptDataProvider
-     */
-    public function propertiesAreUpdatedFromTypoScript(array $typoScript, $globalThemeName, array $expected)
-    {
-        $this->typoScriptRepositoryProphecy
-            ->getModelConfigurationByScope('FORM', 'themeName')
-            ->willReturn($globalThemeName);
-
-        $this->subject->setTypoScript($typoScript);
-        $this->assertEquals($expected['prefix'], $this->subject->getPrefix());
-        $this->assertEquals($expected['contentElementRendering'], $this->subject->getContentElementRendering());
-    }
-
-    /**
-     * @return array
-     */
-    public function propertiesAreUpdatedFromTypoScriptDataProvider()
-    {
-        return [
-            '#1' => [
-                [
-                    'prefix' => '',
-                    'themeName' => '',
-                    'disableContentElement' => false,
-                ],
-                '',
-                [
-                    'prefix' => 'form',
-                    'themeName' => 'Default',
-                    'contentElementRendering' => true,
-                ],
-            ],
-            '#2' => [
-                [
-                    'prefix' => 'somePrefix',
-                    'themeName' => 'someTheme',
-                    'disableContentElement' => true,
-                ],
-                '',
-                [
-                    'prefix' => 'somePrefix',
-                    'themeName' => 'someTheme',
-                    'contentElementRendering' => false,
-                ],
-            ],
-            '#3' => [
-                [
-                    'prefix' => 'somePrefix',
-                    'themeName' => 'someTheme',
-                    'disableContentElement' => true,
-                ],
-                '',
-                [
-                    'prefix' => 'somePrefix',
-                    'themeName' => 'someTheme',
-                    'contentElementRendering' => false,
-                ],
-            ],
-            '#4' => [
-                [
-                    'prefix' => 'somePrefix',
-                    'themeName' => 'someTheme',
-                    'disableContentElement' => true,
-                ],
-                '',
-                [
-                    'prefix' => 'somePrefix',
-                    'themeName' => 'someTheme',
-                    'contentElementRendering' => false,
-                ],
-            ],
-        ];
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Filter/AlphabeticFilterTest.php b/typo3/sysext/form/Tests/Unit/Filter/AlphabeticFilterTest.php
deleted file mode 100644
index 5c45350e5dd4c9c02e22c0793023ae6b5dd4f76e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Filter/AlphabeticFilterTest.php
+++ /dev/null
@@ -1,56 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class AlphabeticFilterTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
-{
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Filter\AlphabeticFilter
-     */
-    protected $subject = null;
-
-    /**
-     * Set up
-     */
-    protected function setUp()
-    {
-        $this->subject = new \TYPO3\CMS\Form\Domain\Filter\AlphabeticFilter();
-    }
-
-    /**
-     * @test
-     */
-    public function filterForStringWithUnicodeCharactersAndSpacesReturnsInputString()
-    {
-        $input = 'My name contains äøüößØœ';
-        // This is default, but let's be explicit:
-        $this->subject->setAllowWhiteSpace(true);
-        $this->assertSame($input, $this->subject->filter($input));
-    }
-
-    /**
-     * @test
-     */
-    public function filterForStringWithUnicodeCharactersAndSpacesWithAllowWhitespaceSetToFalseReturnsInputStringWithoutSpaces()
-    {
-        $input = 'My name contains äøüößØœ';
-        $expected = 'MynamecontainsäøüößØœ';
-        $this->subject->setAllowWhiteSpace(false);
-        $this->assertSame($expected, $this->subject->filter($input));
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Filter/AlphanumericFilterTest.php b/typo3/sysext/form/Tests/Unit/Filter/AlphanumericFilterTest.php
deleted file mode 100644
index 3d1c6a30d37593d06cb3a6ac60d81c639e04d8dd..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Filter/AlphanumericFilterTest.php
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class AlphanumericFilterTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
-{
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Filter\AlphanumericFilter
-     */
-    protected $subject = null;
-
-    /**
-     * Set up
-     */
-    protected function setUp()
-    {
-        $this->subject = new \TYPO3\CMS\Form\Domain\Filter\AlphanumericFilter();
-    }
-
-    /**
-     * @test
-     */
-    public function filterForStringWithUnicodeCharactersAndSpacesReturnsInputString()
-    {
-        $input = 'My name contains äøüößØœ';
-        // This is default, but let's be explicit:
-        $this->subject->setAllowWhiteSpace(true);
-        $this->assertSame($input, $this->subject->filter($input));
-    }
-
-    /**
-     * @test
-     */
-    public function filterForStringWithUnicodeCharactersAndSpacesWithAllowWhitespaceSetToFalseReturnsInputStringWithoutSpaces()
-    {
-        $input = 'My name contains äøüößØœ';
-        $expected = 'MynamecontainsäøüößØœ';
-        $this->subject->setAllowWhiteSpace(false);
-        $this->assertSame($expected, $this->subject->filter($input));
-    }
-
-    /**
-     * @test
-     */
-    public function filterAllowsNumericCharacters()
-    {
-        $this->assertSame('foo23bar', $this->subject->filter('foo23bar'));
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Filter/CurrencyFilterTest.php b/typo3/sysext/form/Tests/Unit/Filter/CurrencyFilterTest.php
deleted file mode 100644
index b141ae4db01ecd4453fc369b155719c42c8dcd8b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Filter/CurrencyFilterTest.php
+++ /dev/null
@@ -1,102 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class CurrencyFilterTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
-{
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Filter\CurrencyFilter
-     */
-    protected $subject;
-
-    protected function setUp()
-    {
-        $this->subject = new \TYPO3\CMS\Form\Domain\Filter\CurrencyFilter();
-    }
-
-    public function validDataProvider()
-    {
-        return [
-            '1200 => 1.200,00' => [
-                '1200', // input
-                '.', // thousand separator
-                ',', // decimal point
-                '1.200,00' // expected
-            ],
-            '0 => 0,00' => [
-                '0',
-                null,
-                ',',
-                '0,00'
-            ],
-            '3333.33 => 3,333.33' => [
-                '3333.33',
-                ',',
-                '.',
-                '3,333.33'
-            ],
-            '1099.33 => 1 099,33' => [
-                '1099.33',
-                ' ',
-                ',',
-                '1 099,33'
-            ],
-            '1200,00 => 1.200,00' => [
-                '1200,00', // input
-                '.', // thousand separator
-                ',', // decimal point
-                '1.200,00' // expected
-            ],
-            '1.200,00 => 1.200,00' => [
-                '1.200,00', // input
-                '.', // thousand separator
-                ',', // decimal point
-                '1.200,00' // expected
-            ],
-            '1.200 => 1.200,00' => [
-                '1.200', // input
-                '.', // thousand separator
-                ',', // decimal point
-                '1.200,00' // expected
-            ],
-            '-1 => -1,00' => [
-                '-1', // input
-                '.', // thousand separator
-                ',', // decimal point
-                '-1,00' // expected
-            ],
-            '1.200 => 1.200,00' => [
-                '1.200', // input
-                '.', // thousand separator
-                ',', // decimal point
-                '1.200,00' // expected
-            ],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validDataProvider
-     */
-    public function filterForVariousIntegerInputsReturnsFormattedCurrencyNotation($input, $thousandSeparator, $decimalPoint, $expected)
-    {
-        $this->subject->setThousandSeparator($thousandSeparator);
-        $this->subject->setDecimalsPoint($decimalPoint);
-        $this->assertSame($expected, $this->subject->filter($input));
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Filter/DigitFilterTest.php b/typo3/sysext/form/Tests/Unit/Filter/DigitFilterTest.php
deleted file mode 100644
index e438af25b075c647f5185aa72a5db790a1943a5f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Filter/DigitFilterTest.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class DigitFilterTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
-{
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Filter\DigitFilter
-     */
-    protected $subject;
-
-    protected function setUp()
-    {
-        $this->subject = new \TYPO3\CMS\Form\Domain\Filter\DigitFilter();
-    }
-
-    public function validDataProvider()
-    {
-        return [
-            '1,00 -> 100' => ['1,00', '100'],
-            '1E+49 -> 149' => ['1E+49', '149'],
-            '100 -> 100' => ['100', '100'],
-            '00000 -> 00000' => ['00000', '00000'],
-            'ABCD -> ""' => ['ABCD', ''],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validDataProvider
-     */
-    public function filterForStringsReturnsStringsFilteredToOnlyContainDigits($input, $expected)
-    {
-        $this->assertSame(
-            $expected,
-            $this->subject->filter($input)
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Filter/IntegerFilterTest.php b/typo3/sysext/form/Tests/Unit/Filter/IntegerFilterTest.php
deleted file mode 100644
index 3194a6b0223f9ef7ccb9f33cc4fa74359d379614..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Filter/IntegerFilterTest.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class IntegerFilterTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
-{
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Filter\IntegerFilter
-     */
-    protected $subject;
-
-    protected function setUp()
-    {
-        $this->subject = new \TYPO3\CMS\Form\Domain\Filter\IntegerFilter();
-    }
-
-    public function dataProvider()
-    {
-        return [
-            '"1" -> 1' => ['1', 1],
-            '1 -> 1' => [1, 1],
-            '1.1 -> 1' => [1.1, 1],
-            'a -> 0' => ['a', 0],
-            'a42 -> 0' => ['a42', 0],
-            '-100.00 -> -100' => [-100.00, -100],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider dataProvider
-     */
-    public function filterForVariousInputReturnsInputCastedToInteger($input, $expected)
-    {
-        $this->assertSame(
-            $expected,
-            $this->subject->filter($input)
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Filter/LowerCaseFilterTest.php b/typo3/sysext/form/Tests/Unit/Filter/LowerCaseFilterTest.php
deleted file mode 100644
index 9016aee750e0abe871b7255332889d88596112d9..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Filter/LowerCaseFilterTest.php
+++ /dev/null
@@ -1,56 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class LowerCaseFilterTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
-{
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Filter\LowerCaseFilter
-     */
-    protected $subject;
-
-    protected function setUp()
-    {
-        $this->subject = new \TYPO3\CMS\Form\Domain\Filter\LowerCaseFilter();
-        $GLOBALS['TSFE'] = new \stdClass();
-        $GLOBALS['TSFE']->csConvObj = new \TYPO3\CMS\Core\Charset\CharsetConverter();
-    }
-
-    public function dataProvider()
-    {
-        return [
-            'a -> a' => ['a', 'a'],
-            'A -> a' => ['A', 'a'],
-            'AaA -> aaa' => ['AaA', 'aaa'],
-            'ÜßbÉØ -> üßbéø' => ['ÜßbÉØ', 'üßbéø'],
-            '01A23b -> 01a23b' => ['01A23b', '01a23b'],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider dataProvider
-     */
-    public function filterForVariousInputReturnsLowercasedInput($input, $expected)
-    {
-        $this->assertSame(
-            $expected,
-            $this->subject->filter($input)
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Filter/RegExpFilterTest.php b/typo3/sysext/form/Tests/Unit/Filter/RegExpFilterTest.php
deleted file mode 100644
index 8d1404b495fb2b4003c2e1b58ab3e39bca407a0e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Filter/RegExpFilterTest.php
+++ /dev/null
@@ -1,65 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class RegExpFilterTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
-{
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Filter\RegExpFilter
-     */
-    protected $subject;
-
-    protected function setUp()
-    {
-        $this->subject = new \TYPO3\CMS\Form\Domain\Filter\RegExpFilter();
-    }
-
-    public function dataProvider()
-    {
-        return [
-            'a-a -> aa for /-/' => [
-                'a-a',
-                '/-/',
-                'aa'
-            ],
-            'aaa -> "" for /.+/' => [
-                'aaa',
-                '/.+/',
-                ''
-            ],
-            'aAa -> aa for /[^a]+/' => [
-                'aAa',
-                '/[^a]+/',
-                'aa'
-            ],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider dataProvider
-     */
-    public function filterForStringReturnsInputWithoutCharactersMatchedByRegularExpression($input, $regularExpression, $expected)
-    {
-        $this->subject->setRegularExpression($regularExpression);
-        $this->assertSame(
-            $expected,
-            $this->subject->filter($input)
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Filter/StripNewLinesFilterTest.php b/typo3/sysext/form/Tests/Unit/Filter/StripNewLinesFilterTest.php
deleted file mode 100644
index 9aa3b16006f02898f8fb9f541157ac78b74fd869..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Filter/StripNewLinesFilterTest.php
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class StripNewLinesFilterTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
-{
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Filter\StripNewLinesFilter
-     */
-    protected $subject = null;
-
-    /**
-     * Set up
-     */
-    protected function setUp()
-    {
-        $this->subject = new \TYPO3\CMS\Form\Domain\Filter\StripNewLinesFilter();
-    }
-
-    public function dataProviderWithNewlines()
-    {
-        return [
-            'some\rtext' => ["some\rtext", 'some text'],
-            'some\ntext' => ["some\ntext", 'some text'],
-            'some\r\ntext' => ["some\r\ntext", 'some text'],
-            'somechr(13)text' => ['some' . chr(13) . 'text', 'some text'],
-            'somechr(10)text' => ['some' . chr(10) . 'text', 'some text'],
-            'somechr(13)chr(10)text' => ['some' . chr(13) . chr(10) . 'text', 'some text'],
-            'someCRtext' => ['some' . CR . 'text', 'some text'],
-            'someLFtext' => ['some' . LF . 'text', 'some text'],
-            'someCRLFtext' => ['some' . CRLF . 'text', 'some text'],
-            'some^Mtext' => ['some
-text', 'some text'],
-            'trailing newline\r' => ["trailing newline\n", 'trailing newline '],
-            'trailing newline\n' => ["trailing newline\r", 'trailing newline '],
-            'trailing newline\r\n' => ["trailing newline\r\n", 'trailing newline '],
-            'trailing newlinechr(13)' => ['trailing newline' . chr(13), 'trailing newline '],
-            'trailing newlinechr(10)' => ['trailing newline' . chr(10), 'trailing newline '],
-            'trailing newlinechr(13)chr(10)' => ['trailing newline' . chr(13) . chr(10), 'trailing newline '],
-            'trailing newlineCR' => ['trailing newline' . CR, 'trailing newline '],
-            'trailing newlineLF' => ['trailing newline' . LF, 'trailing newline '],
-            'trailing newlineCRLF' => ['trailing newline' . CRLF, 'trailing newline '],
-            'trailing newline^M' => ['trailing newline
-', 'trailing newline ']
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider dataProviderWithNewlines
-     */
-    public function filterForStringWithNewlineReturnsStringWithoutNewline($input, $expected)
-    {
-        $this->assertSame(
-            $expected,
-            $this->subject->filter($input)
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Filter/TitleCaseFilterTest.php b/typo3/sysext/form/Tests/Unit/Filter/TitleCaseFilterTest.php
deleted file mode 100644
index 79a40462f3f488528527129ef3346561cf3ddd40..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Filter/TitleCaseFilterTest.php
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Charset\CharsetConverter;
-use TYPO3\CMS\Form\Domain\Filter\TitleCaseFilter;
-
-/**
- * Test case
- */
-class TitleCaseFilterTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
-{
-    /**
-     * @var TitleCaseFilter
-     */
-    protected $subject = null;
-
-    /**
-     * Set up
-     */
-    protected function setUp()
-    {
-        $this->subject = new TitleCaseFilter();
-        $GLOBALS['TSFE'] = new \stdClass();
-        $GLOBALS['TSFE']->csConvObj = new CharsetConverter();
-    }
-
-    /**
-     * @return array
-     */
-    public function stringProvider()
-    {
-        return [
-            'some text' => ['some text', 'Some Text'],
-            'some Text' => ['some Text', 'Some Text'],
-            'Ein Maß' => ['Ein Maß', 'Ein Maß'],
-            '¿por que?' => ['¿por que?', '¿por Que?'],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider stringProvider
-     */
-    public function filterForStringReturnsStringWithUppercasedWords($input, $expected)
-    {
-        $this->assertSame(
-            $expected,
-            $this->subject->filter($input)
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Filter/TrimFilterTest.php b/typo3/sysext/form/Tests/Unit/Filter/TrimFilterTest.php
deleted file mode 100644
index d091186d8157c532ff972c41435a716958694790..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Filter/TrimFilterTest.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class TrimFilterTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
-{
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Filter\TrimFilter
-     */
-    protected $subject = null;
-
-    /**
-     * Set up
-     */
-    protected function setUp()
-    {
-        $this->subject = new \TYPO3\CMS\Form\Domain\Filter\TrimFilter();
-    }
-
-    public function stringProvider()
-    {
-        return [
-            '\tsome text ' => ["\tsome text ", 'some text'],
-            'some text   ' => ['some text   ', 'some text'],
-            'some text^M' => ['some text
-', 'some text'],
-        ];
-    }
-
-    public function stringProviderForCharacterList()
-    {
-        return [
-            '$some text;' => ['$some text;', 'some text', '$;'],
-            '$some text ' => ['$some text ', 'some text', '$ '],
-            '^Msome text ' => ['
-some text ', 'some text', '
- '],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider stringProvider
-     */
-    public function filterForStringWithWhitespaceInFrontAndEndReturnsStringWithoutThisWhitespace($input, $expected)
-    {
-        $this->assertSame(
-            $expected,
-            $this->subject->filter($input)
-        );
-    }
-
-    /**
-     * @test
-     * @dataProvider stringProviderForCharacterList
-     */
-    public function filterForStringWithCharactersInCharacterListReturnsStringWithoutTheseCharacters($input, $expected, $characterList)
-    {
-        $this->subject->setCharacterList($characterList);
-
-        $this->assertSame(
-            $expected,
-            $this->subject->filter($input)
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Filter/UpperCaseFilterTest.php b/typo3/sysext/form/Tests/Unit/Filter/UpperCaseFilterTest.php
deleted file mode 100644
index 37319a272a299b46ab2b061e02158ee7a8566457..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Filter/UpperCaseFilterTest.php
+++ /dev/null
@@ -1,56 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Filter;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class UpperCaseFilterTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
-{
-    /**
-     * @var \TYPO3\CMS\Form\Domain\Filter\UpperCaseFilter
-     */
-    protected $subject = null;
-
-    /**
-     * Set up
-     */
-    protected function setUp()
-    {
-        $this->subject = new \TYPO3\CMS\Form\Domain\Filter\UpperCaseFilter();
-        $GLOBALS['TSFE'] = new \stdClass();
-        $GLOBALS['TSFE']->csConvObj = new \TYPO3\CMS\Core\Charset\CharsetConverter();
-    }
-
-    public function stringProvider()
-    {
-        return [
-            'asdf' => ['asdf', 'ASDF'],
-            'as?df' => ['as?df', 'AS?DF'],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider stringProvider
-     */
-    public function filterForStringReturnsUppercasedString($input, $expected)
-    {
-        $this->assertSame(
-            $expected,
-            $this->subject->filter($input)
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Fixtures/PostProcessorWithFormPrefixFixture.php b/typo3/sysext/form/Tests/Unit/Fixtures/PostProcessorWithFormPrefixFixture.php
deleted file mode 100644
index eb7df1475aa17f0e528f6fb8a4521ab87a968350..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Fixtures/PostProcessorWithFormPrefixFixture.php
+++ /dev/null
@@ -1,47 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Fixtures;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Form\PostProcess\AbstractPostProcessor;
-use TYPO3\CMS\Form\PostProcess\PostProcessorInterface;
-
-/**
- * Post processor with form prefix fixture
- */
-class PostProcessorWithFormPrefixFixture extends AbstractPostProcessor implements PostProcessorInterface
-{
-    /**
-     * @param \TYPO3\CMS\Form\Domain\Model\Element $form
-     * @param array $typoScript
-     */
-    public function __construct(\TYPO3\CMS\Form\Domain\Model\Element $form, array $typoScript)
-    {
-    }
-
-    /**
-     * @param \TYPO3\CMS\Form\Mvc\Controller\ControllerContext $controllerContext
-     */
-    public function setControllerContext(\TYPO3\CMS\Form\Mvc\Controller\ControllerContext $controllerContext)
-    {
-    }
-
-    /**
-     * @return string
-     */
-    public function process()
-    {
-        return 'processedWithPrefix';
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Fixtures/PostProcessorWithoutFormPrefixFixture.php b/typo3/sysext/form/Tests/Unit/Fixtures/PostProcessorWithoutFormPrefixFixture.php
deleted file mode 100644
index 2bfb626408ab04ceca965976af7ab17f8e4dda84..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Fixtures/PostProcessorWithoutFormPrefixFixture.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Fixtures;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Form\PostProcess\AbstractPostProcessor;
-use TYPO3\CMS\Form\PostProcess\PostProcessorInterface;
-
-/**
- * Post processor without form prefix fixture
- */
-class PostProcessorWithoutFormPrefixFixture extends AbstractPostProcessor implements PostProcessorInterface
-{
-    /**
-     * @param \TYPO3\CMS\Form\Domain\Model\Element $form
-     * @param array $typoScript
-     */
-    public function __construct(\TYPO3\CMS\Form\Domain\Model\Element $form, array $typoScript)
-    {
-    }
-
-    /**
-     * @return string
-     */
-    public function process()
-    {
-        return 'processedWithoutPrefix';
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Fixtures/PostProcessorWithoutInterfaceFixture.php b/typo3/sysext/form/Tests/Unit/Fixtures/PostProcessorWithoutInterfaceFixture.php
deleted file mode 100644
index 5b49b62e84e38180403b9b983c0b112efccc16e0..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Fixtures/PostProcessorWithoutInterfaceFixture.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Fixtures;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Post processor with form prefix fixture
- */
-class PostProcessorWithoutInterfaceFixture
-{
-    /**
-     * @param \TYPO3\CMS\Form\Domain\Model\Element $form
-     * @param array $typoScript
-     */
-    public function __construct(\TYPO3\CMS\Form\Domain\Model\Element $form, array $typoScript)
-    {
-    }
-
-    /**
-     * @return string
-     */
-    public function process()
-    {
-        return 'withoutInterface';
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Hooks/DataStructureIdentifierHookTest.php b/typo3/sysext/form/Tests/Unit/Hooks/DataStructureIdentifierHookTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..bea5013271e700bf911c7177485af99eb64e3701
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Hooks/DataStructureIdentifierHookTest.php
@@ -0,0 +1,240 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Hooks;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook;
+use TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager;
+use TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManagerInterface;
+
+/**
+ * Test case
+ */
+class DataStructureIdentifierHookTest extends UnitTestCase
+{
+    /**
+     * @var array A backup of registered singleton instances
+     */
+    protected $singletonInstances = [];
+
+    /**
+     * Set up
+     */
+    public function setUp()
+    {
+        $this->singletonInstances = GeneralUtility::getSingletonInstances();
+    }
+
+    /**
+     * Tear down
+     */
+    public function tearDown()
+    {
+        GeneralUtility::resetSingletonInstances($this->singletonInstances);
+        parent::tearDown();
+    }
+
+    /**
+     * @test
+     */
+    public function getDataStructureIdentifierPostProcessReturnsIdentifierForNotMatchingScenario()
+    {
+        $givenIdentifier = ['aKey' => 'aValue'];
+        $result = (new DataStructureIdentifierHook())->getDataStructureIdentifierPostProcess(
+            [], 'aTable', 'aField', [], $givenIdentifier
+        );
+        $this->assertEquals($givenIdentifier, $result);
+    }
+
+    /**
+     * @test
+     */
+    public function getDataStructureIdentifierPostProcessAddDefaultValuesForNewRecord()
+    {
+        $result = (new DataStructureIdentifierHook())->getDataStructureIdentifierPostProcess(
+            [], 'tt_content', 'pi_flexform', ['CType' => 'form_formframework'], []
+        );
+        $this->assertEquals(
+            ['ext-form-persistenceIdentifier' => '', 'ext-form-overrideFinishers' => false],
+            $result
+        );
+    }
+
+    /**
+     * @test
+     */
+    public function getDataStructureIdentifierPostProcessAddsGivenPersistenceIdentifier()
+    {
+        $row = [
+            'CType' => 'form_formframework',
+            'pi_flexform' => '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+                <T3FlexForms>
+                    <data>
+                        <sheet index="sDEF">
+                            <language index="lDEF">
+                                <field index="settings.persistenceIdentifier">
+                                    <value index="vDEF">1:user_upload/karl.yml</value>
+                                </field>
+                            </language>
+                        </sheet>
+                    </data>
+                </T3FlexForms>
+            ',
+        ];
+        $incomingIdentifier = [
+            'aKey' => 'aValue',
+        ];
+        $expected = [
+            'aKey' => 'aValue',
+            'ext-form-persistenceIdentifier' => '1:user_upload/karl.yml',
+            'ext-form-overrideFinishers' => false,
+        ];
+        $result = (new DataStructureIdentifierHook())->getDataStructureIdentifierPostProcess(
+            [], 'tt_content', 'pi_flexform', $row, $incomingIdentifier
+        );
+        $this->assertEquals($expected, $result);
+    }
+
+    /**
+     * @test
+     */
+    public function getDataStructureIdentifierPostProcessAddsOverrideFinisherValue()
+    {
+        $row = [
+            'CType' => 'form_formframework',
+            'pi_flexform' => '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+                <T3FlexForms>
+                    <data>
+                        <sheet index="sDEF">
+                            <language index="lDEF">
+                                <field index="settings.overrideFinishers">
+                                    <value index="vDEF">1</value>
+                               </field>
+                            </language>
+                        </sheet>
+                    </data>
+                </T3FlexForms>
+            ',
+        ];
+        $expected = [
+            'ext-form-persistenceIdentifier' => '',
+            'ext-form-overrideFinishers' => true,
+        ];
+        $result = (new DataStructureIdentifierHook())->getDataStructureIdentifierPostProcess(
+            [], 'tt_content', 'pi_flexform', $row, []
+        );
+        $this->assertEquals($expected, $result);
+    }
+
+    /**
+     * @test
+     */
+    public function parseDataStructureByIdentifierPostProcessReturnsDataStructureUnchanged()
+    {
+        $dataStructure = ['foo' => 'bar'];
+        $expected = $dataStructure;
+        $result = (new DataStructureIdentifierHook())->parseDataStructureByIdentifierPostProcess(
+            $dataStructure, []
+        );
+        $this->assertEquals($expected, $result);
+    }
+
+    /**
+     * @test
+     */
+    public function parseDataStructureByIdentifierPostProcessAddsExistingFormItems()
+    {
+        $objectMangerProphecy = $this->prophesize(ObjectManager::class);
+        GeneralUtility::setSingletonInstance(ObjectManager::class, $objectMangerProphecy->reveal());
+        $formPersistenceManagerProphecy = $this->prophesize(FormPersistenceManager::class);
+        $objectMangerProphecy->get(FormPersistenceManagerInterface::class)
+            ->willReturn($formPersistenceManagerProphecy->reveal());
+
+        $existingForms = [
+            [
+                'persistenceIdentifier' => 'hugo1',
+                'name' => 'myHugo1',
+            ],
+            [
+                'persistenceIdentifier' => 'hugo2',
+                'name' => 'myHugo2',
+            ]
+        ];
+        $formPersistenceManagerProphecy->listForms()->shouldBeCalled()->willReturn($existingForms);
+
+        $incomingDataStructure = [
+            'sheets' => [
+                'sDEF' => [
+                    'ROOT' => [
+                        'el' => [
+                            'settings.persistenceIdentifier' => [
+                                'TCEforms' => [
+                                    'config' => [
+                                        'items' => [
+                                            0 => [
+                                                0 => 'default, no value',
+                                                1 => '',
+                                            ],
+                                        ],
+                                    ],
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $expected = [
+            'sheets' => [
+                'sDEF' => [
+                    'ROOT' => [
+                        'el' => [
+                            'settings.persistenceIdentifier' => [
+                                'TCEforms' => [
+                                    'config' => [
+                                        'items' => [
+                                            0 => [
+                                                0 => 'default, no value',
+                                                1 => '',
+                                            ],
+                                            1 => [
+                                                0 => 'myHugo1 (hugo1)',
+                                                1 => 'hugo1',
+                                            ],
+                                            2 => [
+                                                0 => 'myHugo2 (hugo2)',
+                                                1 => 'hugo2',
+                                            ],
+                                        ],
+                                    ],
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $result = (new DataStructureIdentifierHook())->parseDataStructureByIdentifierPostProcess(
+            $incomingDataStructure,
+            ['ext-form-persistenceIdentifier' => '']
+        );
+
+        $this->assertEquals($expected, $result);
+    }
+}
diff --git a/typo3/sysext/form/Tests/Unit/Mvc/Configuration/Fixtures/Header.yaml b/typo3/sysext/form/Tests/Unit/Mvc/Configuration/Fixtures/Header.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ab19ab69cdc88804edfa3c1c3e59650c25149a07
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Mvc/Configuration/Fixtures/Header.yaml
@@ -0,0 +1,6 @@
+# Header 1
+# Header 2
+
+yaml
+
+# Comment
\ No newline at end of file
diff --git a/typo3/sysext/form/Tests/Unit/Mvc/Configuration/Fixtures/Invalid.yaml b/typo3/sysext/form/Tests/Unit/Mvc/Configuration/Fixtures/Invalid.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..261338580151f403c7d395faaad662d097e8fb05
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Mvc/Configuration/Fixtures/Invalid.yaml
@@ -0,0 +1,2 @@
+key
+  yek
\ No newline at end of file
diff --git a/typo3/sysext/form/Tests/Unit/Mvc/Configuration/InheritancesResolverServiceTest.php b/typo3/sysext/form/Tests/Unit/Mvc/Configuration/InheritancesResolverServiceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0e7b33216a6a4da967a781f4a105565ddc74edd0
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Mvc/Configuration/InheritancesResolverServiceTest.php
@@ -0,0 +1,429 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Mvc\Configuration;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Form\Mvc\Configuration\Exception\CycleInheritancesException;
+use TYPO3\CMS\Form\Mvc\Configuration\InheritancesResolverService;
+
+/**
+ * Test case
+ */
+class InheritancesResolverServiceTest extends UnitTestCase
+{
+    /**
+     * @var InheritancesResolverService
+     */
+    protected $subject;
+
+    protected function setUp()
+    {
+        $this->subject = new InheritancesResolverService();
+    }
+
+    /**
+     * @test
+     */
+    public function getMergedConfigurationSimpleInheritance()
+    {
+        $input = [
+            'Form' => [
+                'klaus01' => [
+                    'key01' => 'value',
+                    'key02' => [
+                        'key03' => 'value',
+                    ],
+                ],
+                'klaus02' => [
+                    '__inheritances' => [
+                        10 => 'Form.klaus01',
+                    ],
+                ],
+            ],
+        ];
+
+        $expected = [
+            'Form' => [
+                'klaus01' => [
+                    'key01' => 'value',
+                    'key02' => [
+                        'key03' => 'value'
+                    ],
+                ],
+                'klaus02' => [
+                    'key01' => 'value',
+                    'key02' => [
+                        'key03' => 'value',
+                    ],
+                ],
+            ],
+        ];
+
+        $this->assertSame($expected, $this->subject->reset()->setReferenceConfiguration($input)->getResolvedConfiguration($input));
+    }
+
+    /**
+     * @test
+     */
+    public function getMergedConfigurationSimpleInheritanceOverrideValue()
+    {
+        $input = [
+            'Form' => [
+                'klaus01' => [
+                    'key' => 'value',
+                ],
+                'klaus02' => [
+                    '__inheritances' => [
+                        10 => 'Form.klaus01',
+                    ],
+                    'key' => 'value override',
+                ],
+            ],
+        ];
+
+        $expected = [
+            'Form' => [
+                'klaus01' => [
+                    'key' => 'value',
+                ],
+                'klaus02' => [
+                    'key' => 'value override',
+                ],
+            ],
+        ];
+
+        $this->assertSame($expected, $this->subject->reset()->setReferenceConfiguration($input)->getResolvedConfiguration($input));
+    }
+
+    /**
+     * @test
+     */
+    public function getMergedConfigurationSimpleInheritanceRemoveValue()
+    {
+        $input = [
+            'Form' => [
+                'klaus01' => [
+                    'key01' => [
+                        'key02' => 'value',
+                    ],
+                    'key02' => [
+                        10 => [
+                            'key' => 'value',
+                        ],
+                        20 => [
+                            'key' => 'value',
+                        ],
+                    ],
+                ],
+                'klaus02' => [
+                    '__inheritances' => [
+                        10 => 'Form.klaus01',
+                    ],
+                    'key01' => null,
+                    'key02' => [
+                        10 => null,
+                        20 => [
+                            'key' => null,
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $expected = [
+            'Form' => [
+                'klaus01' => [
+                    'key01' => [
+                        'key02' => 'value',
+                    ],
+                    'key02' => [
+                        10 => [
+                            'key' => 'value',
+                        ],
+                        20 => [
+                            'key' => 'value',
+                        ],
+                    ],
+                ],
+                'klaus02' => [
+                    'key01' => null,
+                    'key02' => [
+                        10 => null,
+                        20 => [
+                            'key' => null,
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $this->assertSame($expected, $this->subject->reset()->setReferenceConfiguration($input)->getResolvedConfiguration($input));
+    }
+
+    /**
+     * @test
+     */
+    public function getMergedConfigurationSimpleMixin()
+    {
+        $input = [
+            'Form' => [
+                'mixin01' => [
+                    'key' => 'value',
+                ],
+                'klaus01' => [
+                    '__inheritances' => [
+                        10 => 'Form.mixin01',
+                    ],
+                ],
+                'klaus02' => [
+                    'key' => [
+                        '__inheritances' => [
+                            10 => 'Form.mixin01',
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $expected = [
+            'Form' => [
+                'mixin01' => [
+                    'key' => 'value',
+                ],
+                'klaus01' => [
+                    'key' => 'value',
+                ],
+                'klaus02' => [
+                    'key' => [
+                        'key' => 'value',
+                    ],
+                ],
+            ],
+        ];
+
+        $this->assertSame($expected, $this->subject->reset()->setReferenceConfiguration($input)->getResolvedConfiguration($input));
+    }
+
+    /**
+     * @test
+     */
+    public function getMergedConfigurationAdvancedMixin()
+    {
+        $input = [
+            'Form' => [
+                'mixin01' => [
+                    'key01' => 'value01',
+                    'key02' => 'value02',
+                ],
+                'mixin02' => [
+                    '__inheritances' => [
+                        10 => 'Form.mixin01',
+                    ],
+                ],
+                'mixin03' => [
+                    'key03' => 'value03',
+                ],
+
+                'klaus01' => [
+                    '__inheritances' => [
+                        10 => 'Form.mixin01',
+                    ],
+                    'key01' => 'value01 override 01',
+                ],
+                'klaus02' => [
+                    '__inheritances' => [
+                        10 => 'Form.klaus01',
+                        20 => 'Form.mixin03',
+                    ],
+                    'key01' => 'value01 override 02',
+                    'key02' => [
+                        'horst01' => 'gerda01'
+                    ],
+                    'key03' => [
+                        '__inheritances' => [
+                            10 => 'Form.mixin02',
+                        ],
+                        'key02' => null,
+                    ],
+                ],
+                'klaus03' => [
+                    '__inheritances' => [
+                        10 => 'Form.klaus02',
+                    ],
+                ],
+            ],
+        ];
+
+        $expected = [
+            'Form' => [
+                'mixin01' => [
+                    'key01' => 'value01',
+                    'key02' => 'value02',
+                ],
+                'mixin02' => [
+                    'key01' => 'value01',
+                    'key02' => 'value02',
+                ],
+                'mixin03' => [
+                    'key03' => 'value03',
+                ],
+                'klaus01' => [
+                    'key01' => 'value01 override 01',
+                    'key02' => 'value02',
+                ],
+                'klaus02' => [
+                    'key01' => 'value01 override 02',
+                    'key02' => [
+                        'horst01' => 'gerda01'
+                    ],
+                    'key03' => [
+                        'key01' => 'value01',
+                        'key02' => null,
+                    ],
+                ],
+                'klaus03' => [
+                    'key01' => 'value01 override 02',
+                    'key02' => [
+                        'horst01' => 'gerda01'
+                    ],
+                    'key03' => [
+                        'key01' => 'value01',
+                        'key02' => null,
+                    ],
+                ],
+            ],
+        ];
+
+        $this->assertSame($expected, $this->subject->reset()->setReferenceConfiguration($input)->getResolvedConfiguration($input));
+    }
+
+    /**
+     * @test
+     */
+    public function getResolvedConfigurationThrowsExceptionIfCycleDepenciesOnSameLevelIsFound()
+    {
+        $input = [
+            'TYPO3' => [
+                'CMS' => [
+                    'Form' => [
+                        'someKey' => [
+                            '__inheritances' => [
+                                10 => 'TYPO3.CMS.Form.anotherKey',
+                            ],
+                        ],
+                        'anotherKey' => [
+                            '__inheritances' => [
+                                10 => 'TYPO3.CMS.Form.someKey',
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $this->expectException(CycleInheritancesException::class);
+        $this->expectExceptionCode(1474900797);
+
+        $this->subject->reset()->setReferenceConfiguration($input)->getResolvedConfiguration($input);
+    }
+
+    /**
+     * @test
+     */
+    public function getResolvedConfigurationThrowsExceptionIfCycleDepenciesOnSameLevelWithGapIsFound()
+    {
+        $input = [
+            'TYPO3' => [
+                'CMS' => [
+                    'Form' => [
+                        'klaus1' => [
+                            '__inheritances' => [
+                                10 => 'TYPO3.CMS.Form.klaus2',
+                            ],
+                        ],
+                        'klaus2' => [
+                            '__inheritances' => [
+                                10 => 'TYPO3.CMS.Form.mixin1',
+                            ],
+                        ],
+                        'mixin1' => [
+                            '__inheritances' => [
+                                10 => 'TYPO3.CMS.Form.mixin2',
+                            ],
+                        ],
+                        'mixin2' => [
+                            '__inheritances' => [
+                                10 => 'TYPO3.CMS.Form.klaus2',
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $this->expectException(CycleInheritancesException::class);
+        $this->expectExceptionCode(1474900799);
+
+        $this->subject->reset()->setReferenceConfiguration($input)->getResolvedConfiguration($input);
+    }
+
+    /**
+     * @test
+     */
+    public function getResolvedConfigurationThrowsExceptionIfCycleDepenciesOnHigherLevelIsFound()
+    {
+        $input = [
+            'TYPO3' => [
+                'CMS' => [
+                    'Form' => [
+                        'klaus1' => [
+                            'key01' => 'value',
+                            'key02' => [
+                                '__inheritances' => [
+                                    10 => 'TYPO3.CMS.Form.mixin01',
+                                ],
+                            ],
+                        ],
+                        'klaus2' => [
+                            '__inheritances' => [
+                                10 => 'TYPO3.CMS.Form.klaus1',
+                            ],
+                            'key02' => [
+                                '__inheritances' => [
+                                    10 => 'TYPO3.CMS.Form.mixin01',
+                                    20 => 'TYPO3.CMS.Form.mixin02',
+                                ],
+                            ],
+                        ],
+                        'mixin01' => [
+                            'liselotte01' => 'value',
+                        ],
+                        'mixin02' => [
+                            '__inheritances' => [
+                                10 => 'TYPO3.CMS.Form.klaus2',
+                            ],
+                            'liselotte02' => 'value',
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $this->expectException(CycleInheritancesException::class);
+        $this->expectExceptionCode(1474900797);
+
+        $this->subject->reset()->setReferenceConfiguration($input)->getResolvedConfiguration($input);
+    }
+}
diff --git a/typo3/sysext/form/Tests/Unit/Mvc/Configuration/TypoScriptServiceTest.php b/typo3/sysext/form/Tests/Unit/Mvc/Configuration/TypoScriptServiceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..31e89dbbbedd19eab5d908cd6e2fbc75352ac9e5
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Mvc/Configuration/TypoScriptServiceTest.php
@@ -0,0 +1,69 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Mvc\Configuration;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Form\Mvc\Configuration\TypoScriptService;
+use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
+
+/**
+ * Test case
+ */
+class TypoScriptServiceTest extends UnitTestCase
+{
+    /**
+     * @test
+     */
+    public function resolveTypoScriptConfigurationReturnsResolvedConfiguration()
+    {
+        $mockTypoScriptService = $this->getAccessibleMock(TypoScriptService::class, [
+            'getTypoScriptFrontendController'
+        ], [], '', false);
+
+        $mockContentObjectRenderer = $this->getMockBuilder(
+            ContentObjectRenderer::class
+        )->getMock();
+
+        $fakeTypoScriptFrontendController = new \stdClass;
+        $fakeTypoScriptFrontendController->cObj = $mockContentObjectRenderer;
+
+        $mockContentObjectRenderer
+            ->expects($this->any())
+            ->method('cObjGetSingle')
+            ->with('TEXT', ['value' => 'rambo'])
+            ->will($this->returnValue('rambo'));
+
+        $mockTypoScriptService
+            ->expects($this->any())
+            ->method('getTypoScriptFrontendController')
+            ->willReturn($fakeTypoScriptFrontendController);
+
+        $input = [
+            'key.' => [
+                'john' => 'TEXT',
+                'john.' => [
+                    'value' => 'rambo'
+                ],
+            ],
+        ];
+        $expected = [
+            'key' => [
+                'john' => 'rambo',
+            ],
+        ];
+
+        $this->assertSame($expected, $mockTypoScriptService->_call('resolveTypoScriptConfiguration', $input));
+    }
+}
diff --git a/typo3/sysext/form/Tests/Unit/Mvc/Configuration/YamlSourceTest.php b/typo3/sysext/form/Tests/Unit/Mvc/Configuration/YamlSourceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..faf1ab90929a191147368488a21364cc507d52bd
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Mvc/Configuration/YamlSourceTest.php
@@ -0,0 +1,107 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Mvc\Configuration;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Form\Mvc\Configuration\Exception\NoSuchFileException;
+use TYPO3\CMS\Form\Mvc\Configuration\Exception\ParseErrorException;
+use TYPO3\CMS\Form\Mvc\Configuration\YamlSource;
+
+/**
+ * Test case
+ */
+class YamlSourceTest extends UnitTestCase
+{
+
+    /**
+     * @test
+     */
+    public function loadThrowsExceptionIfFileToLoadNotExists()
+    {
+        $this->expectException(NoSuchFileException::class);
+        $this->expectExceptionCode(1471473378);
+
+        $mockYamlSource = $this->getAccessibleMock(YamlSource::class, [
+            'dummy',
+        ], [], '', false);
+
+        $input = [
+            'EXT:form/Resources/Forms/_example.yaml'
+        ];
+
+        $mockYamlSource->_call('load', $input);
+    }
+
+    /**
+     * @test
+     */
+    public function loadThrowsExceptionIfFileToLoadIsNotValidYamlUseSymfonyParser()
+    {
+        if (!extension_loaded('yaml')) {
+            $this->expectException(ParseErrorException::class);
+            $this->expectExceptionCode(1480195405);
+
+            $mockYamlSource = $this->getAccessibleMock(YamlSource::class, [
+                'dummy',
+            ], [], '', false);
+
+            $input = [
+                'EXT:form/Tests/Unit/Mvc/Configuration/Fixtures/Invalid.yaml'
+            ];
+
+            $mockYamlSource->_call('load', $input);
+        }
+    }
+
+    /**
+     * @test
+     */
+    public function loadThrowsExceptionIfFileToLoadIsNotValidYamlUsePhpExtensionParser()
+    {
+        if (extension_loaded('yaml')) {
+            $this->expectException(ParseErrorException::class);
+            $this->expectExceptionCode(1391894094);
+
+            $mockYamlSource = $this->getAccessibleMock(YamlSource::class, [
+                'dummy',
+            ], [], '', false);
+
+            $input = [
+                'EXT:form/Tests/Unit/Mvc/Configuration/Fixtures/Invalid.yaml'
+            ];
+
+            $mockYamlSource->_call('load', $input);
+        }
+    }
+
+    /**
+     * @test
+     */
+    public function getHeaderFromFileReturnsHeaderPart()
+    {
+        $mockYamlSource = $this->getAccessibleMock(YamlSource::class, [
+            'dummy',
+        ], [], '', false);
+
+        $input = GeneralUtility::getFileAbsFileName('EXT:form/Tests/Unit/Mvc/Configuration/Fixtures/Header.yaml');
+        $expected =
+'# Header 1
+# Header 2
+';
+
+        $this->assertSame($expected, $mockYamlSource->_call('getHeaderFromFile', $input));
+    }
+}
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/ContentElement.html b/typo3/sysext/form/Tests/Unit/Mvc/Persistence/Fixtures/BlankForm.txt
similarity index 100%
rename from typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/ContentElement.html
rename to typo3/sysext/form/Tests/Unit/Mvc/Persistence/Fixtures/BlankForm.txt
diff --git a/typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Header.html b/typo3/sysext/form/Tests/Unit/Mvc/Persistence/Fixtures/BlankForm.yaml
similarity index 100%
rename from typo3/sysext/form/Resources/Private/Partials/Default/Confirmation/FlatElements/Header.html
rename to typo3/sysext/form/Tests/Unit/Mvc/Persistence/Fixtures/BlankForm.yaml
diff --git a/typo3/sysext/form/Tests/Unit/Mvc/Persistence/FormPersistenceManagerTest.php b/typo3/sysext/form/Tests/Unit/Mvc/Persistence/FormPersistenceManagerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c4c32805db78f405ce270d97a5c22afbf9f95b58
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Mvc/Persistence/FormPersistenceManagerTest.php
@@ -0,0 +1,617 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Mvc\Persistence;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Resource\File;
+use TYPO3\CMS\Core\Resource\ResourceStorage;
+use TYPO3\CMS\Core\Resource\StorageRepository;
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Form\Mvc\Persistence\Exception\NoUniqueIdentifierException;
+use TYPO3\CMS\Form\Mvc\Persistence\Exception\PersistenceManagerException;
+use TYPO3\CMS\Form\Mvc\Persistence\FormPersistenceManager;
+
+/**
+ * Test case
+ */
+class FormPersistenceManagerTest extends UnitTestCase
+{
+
+    /**
+     * @test
+     */
+    public function loadThrowsExceptionIfPersistenceIdentifierHasNoYamlExtension()
+    {
+        $this->expectException(PersistenceManagerException::class);
+        $this->expectExceptionCode(1477679819);
+
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'dummy'
+        ], [], '', false);
+
+        $input = '-1:/user_uploads/_example.php';
+        $mockFormPersistenceManager->_call('load', $input);
+    }
+
+    /**
+     * @test
+     */
+    public function saveThrowsExceptionIfPersistenceIdentifierHasNoYamlExtension()
+    {
+        $this->expectException(PersistenceManagerException::class);
+        $this->expectExceptionCode(1477679820);
+
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'dummy'
+        ], [], '', false);
+
+        $input = '-1:/user_uploads/_example.php';
+        $mockFormPersistenceManager->_call('save', $input, []);
+    }
+
+    /**
+     * @test
+     */
+    public function saveThrowsExceptionIfPersistenceIdentifierIsAExtensionLocationAndSaveToExtensionLocationIsNotAllowed()
+    {
+        $this->expectException(PersistenceManagerException::class);
+        $this->expectExceptionCode(1477680881);
+
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'dummy'
+        ], [], '', false);
+
+        $mockFormPersistenceManager->_set('formSettings', [
+            'persistenceManager' => [
+                'allowSaveToExtensionPaths' => false,
+            ],
+        ]);
+
+        $input = 'EXT:form/Resources/Forms/_example.yaml';
+        $mockFormPersistenceManager->_call('save', $input, []);
+    }
+
+    /**
+     * @test
+     */
+    public function deleteThrowsExceptionIfPersistenceIdentifierHasNoYamlExtension()
+    {
+        $this->expectException(PersistenceManagerException::class);
+        $this->expectExceptionCode(1472239534);
+
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'dummy'
+        ], [], '', false);
+
+        $input = '-1:/user_uploads/_example.php';
+        $mockFormPersistenceManager->_call('delete', $input);
+    }
+
+    /**
+     * @test
+     */
+    public function deleteThrowsExceptionIfPersistenceIdentifierFileDoesNotExists()
+    {
+        $this->expectException(PersistenceManagerException::class);
+        $this->expectExceptionCode(1472239535);
+
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'exists'
+        ], [], '', false);
+
+        $mockFormPersistenceManager
+            ->expects($this->any())
+            ->method('exists')
+            ->willReturn(false);
+
+        $input = '-1:/user_uploads/_example.yaml';
+        $mockFormPersistenceManager->_call('delete', $input);
+    }
+
+    /**
+     * @test
+     */
+    public function deleteThrowsExceptionIfPersistenceIdentifierIsExtensionLocation()
+    {
+        $this->expectException(PersistenceManagerException::class);
+        $this->expectExceptionCode(1472239536);
+
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'exists'
+        ], [], '', false);
+
+        $mockFormPersistenceManager
+            ->expects($this->any())
+            ->method('exists')
+            ->willReturn(true);
+
+        $input = 'EXT:form/Resources/Forms/_example.yaml';
+        $mockFormPersistenceManager->_call('delete', $input);
+    }
+
+    /**
+     * @test
+     */
+    public function deleteThrowsExceptionIfPersistenceIdentifierIsStorageLocationAndDeleteFromStorageIsNotAllowed()
+    {
+        $this->expectException(PersistenceManagerException::class);
+        $this->expectExceptionCode(1472239516);
+
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'getStorageByUid',
+            'exists'
+        ], [], '', false);
+
+        $mockStorage = $this->getMockBuilder(ResourceStorage::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $mockStorage
+            ->expects($this->any())
+            ->method('checkFileActionPermission')
+            ->willReturn(false);
+
+        $file = new File(['identifier' => '', 'mime_type' => ''], $mockStorage);
+        $mockStorage
+            ->expects($this->any())
+            ->method('getFile')
+            ->willReturn($file);
+
+        $mockFormPersistenceManager
+            ->expects($this->any())
+            ->method('getStorageByUid')
+            ->willReturn($mockStorage);
+
+        $mockFormPersistenceManager
+            ->expects($this->any())
+            ->method('exists')
+            ->willReturn(true);
+
+        $input = '-1:/user_uploads/_example.yaml';
+        $mockFormPersistenceManager->_call('delete', $input);
+    }
+
+    /**
+     * @test
+     */
+    public function existsReturnsTrueIfPersistenceIdentifierIsExtensionLocationAndFileExistsAndFileHasYamlExtension()
+    {
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'dummy'
+        ], [], '', false);
+
+        $input = 'EXT:form/Tests/Unit/Mvc/Persistence/Fixtures/BlankForm.yaml';
+        $this->assertTrue($mockFormPersistenceManager->_call('exists', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function existsReturnsFalseIfPersistenceIdentifierIsExtensionLocationAndFileExistsAndFileHasNoYamlExtension()
+    {
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'dummy'
+        ], [], '', false);
+
+        $input = 'EXT:form/Tests/Unit/Mvc/Persistence/Fixtures/BlankForm.txt';
+        $this->assertFalse($mockFormPersistenceManager->_call('exists', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function existsReturnsFalseIfPersistenceIdentifierIsExtensionLocationAndFileNotExistsAndFileHasYamlExtension()
+    {
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'dummy'
+        ], [], '', false);
+
+        $input = 'EXT:form/Tests/Unit/Mvc/Persistence/Fixtures/_BlankForm.yaml';
+        $this->assertFalse($mockFormPersistenceManager->_call('exists', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function existsReturnsTrueIfPersistenceIdentifierIsStorageLocationAndFileExistsAndFileHasYamlExtension()
+    {
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'getStorageByUid'
+        ], [], '', false);
+
+        $mockStorage = $this->getMockBuilder(ResourceStorage::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $mockStorage
+            ->expects($this->any())
+            ->method('hasFile')
+            ->willReturn(true);
+
+        $mockFormPersistenceManager
+            ->expects($this->any())
+            ->method('getStorageByUid')
+            ->willReturn($mockStorage);
+
+        $input = '-1:/user_uploads/_example.yaml';
+        $this->assertTrue($mockFormPersistenceManager->_call('exists', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function existsReturnsFalseIfPersistenceIdentifierIsStorageLocationAndFileExistsAndFileNoYamlExtension()
+    {
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'getStorageByUid'
+        ], [], '', false);
+
+        $mockStorage = $this->getMockBuilder(ResourceStorage::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $mockStorage
+            ->expects($this->any())
+            ->method('hasFile')
+            ->willReturn(true);
+
+        $mockFormPersistenceManager
+            ->expects($this->any())
+            ->method('getStorageByUid')
+            ->willReturn($mockStorage);
+
+        $input = '-1:/user_uploads/_example.php';
+        $this->assertFalse($mockFormPersistenceManager->_call('exists', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function existsReturnsFalseIfPersistenceIdentifierIsStorageLocationAndFileNotExistsAndFileHasYamlExtension()
+    {
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'getStorageByUid'
+        ], [], '', false);
+
+        $mockStorage = $this->getMockBuilder(ResourceStorage::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $mockStorage
+            ->expects($this->any())
+            ->method('hasFile')
+            ->willReturn(false);
+
+        $mockFormPersistenceManager
+            ->expects($this->any())
+            ->method('getStorageByUid')
+            ->willReturn($mockStorage);
+
+        $input = '-1:/user_uploads/_example.yaml';
+        $this->assertFalse($mockFormPersistenceManager->_call('exists', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function getUniquePersistenceIdentifierAppendNumberIfPersistenceIdentifierExists()
+    {
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'exists'
+        ], [], '', false);
+
+        $mockFormPersistenceManager
+            ->expects($this->at(0))
+            ->method('exists')
+            ->willReturn(true);
+
+        $mockFormPersistenceManager
+            ->expects($this->at(1))
+            ->method('exists')
+            ->willReturn(true);
+
+        $mockFormPersistenceManager
+            ->expects($this->at(2))
+            ->method('exists')
+            ->willReturn(false);
+
+        $input = 'example';
+        $expected = '-1:/user_uploads/example_2.yaml';
+        $this->assertSame($expected, $mockFormPersistenceManager->_call('getUniquePersistenceIdentifier', $input, '-1:/user_uploads/'));
+    }
+
+    /**
+     * @test
+     */
+    public function getUniquePersistenceIdentifierAppendTimestampIfPersistenceIdentifierExists()
+    {
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'exists'
+        ], [], '', false);
+
+        for ($attempts = 0; $attempts <= 99; $attempts++) {
+            $mockFormPersistenceManager
+                ->expects($this->at($attempts))
+                ->method('exists')
+                ->willReturn(true);
+        }
+
+        $mockFormPersistenceManager
+            ->expects($this->at(100))
+            ->method('exists')
+            ->willReturn(false);
+
+        $input = 'example';
+        $expected = '#^-1:/user_uploads/example_([0-9]{10}).yaml$#';
+
+        $returnValue = $mockFormPersistenceManager->_call('getUniquePersistenceIdentifier', $input, '-1:/user_uploads/');
+        $this->assertEquals(1, preg_match($expected, $returnValue));
+    }
+
+    /**
+     * @test
+     */
+    public function getUniqueIdentifierThrowsExceptionIfIdentifierExists()
+    {
+        $this->expectException(NoUniqueIdentifierException::class);
+        $this->expectExceptionCode(1477688567);
+
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'checkForDuplicateIdentifier'
+        ], [], '', false);
+
+        $mockFormPersistenceManager
+            ->expects($this->any())
+            ->method('checkForDuplicateIdentifier')
+            ->willReturn(true);
+
+        $input = 'example';
+        $mockFormPersistenceManager->_call('getUniqueIdentifier', $input);
+    }
+
+    /**
+     * @test
+     */
+    public function getUniqueIdentifierAppendTimestampIfIdentifierExists()
+    {
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'checkForDuplicateIdentifier'
+        ], [], '', false);
+
+        for ($attempts = 0; $attempts <= 99; $attempts++) {
+            $mockFormPersistenceManager
+                ->expects($this->at($attempts))
+                ->method('checkForDuplicateIdentifier')
+                ->willReturn(true);
+        }
+
+        $mockFormPersistenceManager
+            ->expects($this->at(100))
+            ->method('checkForDuplicateIdentifier')
+            ->willReturn(false);
+
+        $input = 'example';
+        $expected = '#^example_([0-9]{10})$#';
+
+        $returnValue = $mockFormPersistenceManager->_call('getUniqueIdentifier', $input);
+        $this->assertEquals(1, preg_match($expected, $returnValue));
+    }
+
+    /**
+     * @test
+     */
+    public function checkForDuplicateIdentifierReturnsTrueIfIdentifierIsUsed()
+    {
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'listForms'
+        ], [], '', false);
+
+        $mockFormPersistenceManager
+            ->expects($this->at($attempts))
+            ->method('listForms')
+            ->willReturn([
+                0 => [
+                    'identifier' => 'example',
+                ],
+            ]);
+
+        $input = 'example';
+        $this->assertTrue($mockFormPersistenceManager->_call('checkForDuplicateIdentifier', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function checkForDuplicateIdentifierReturnsFalseIfIdentifierIsUsed()
+    {
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'listForms'
+        ], [], '', false);
+
+        $mockFormPersistenceManager
+            ->expects($this->at($attempts))
+            ->method('listForms')
+            ->willReturn([
+                0 => [
+                    'identifier' => 'example',
+                ],
+            ]);
+
+        $input = 'other-example';
+        $this->assertFalse($mockFormPersistenceManager->_call('checkForDuplicateIdentifier', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function getFileByIdentifierThrowsExceptionIfReadFromStorageIsNotAllowed()
+    {
+        $this->expectException(PersistenceManagerException::class);
+        $this->expectExceptionCode(1471630578);
+
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'getStorageByUid',
+        ], [], '', false);
+
+        $mockStorage = $this->getMockBuilder(ResourceStorage::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $mockStorage
+            ->expects($this->any())
+            ->method('checkFileActionPermission')
+            ->willReturn(false);
+
+        $file = new File(['identifier' => '', 'mime_type' => ''], $mockStorage);
+        $mockStorage
+            ->expects($this->any())
+            ->method('getFile')
+            ->willReturn($file);
+
+        $mockFormPersistenceManager
+            ->expects($this->any())
+            ->method('getStorageByUid')
+            ->willReturn($mockStorage);
+
+        $input = '-1:/user_uploads/example.yaml';
+        $mockFormPersistenceManager->_call('getFileByIdentifier', $input);
+    }
+
+    /**
+     * @test
+     */
+    public function getOrCreateFileThrowsExceptionIfFolderNotExistsInStorage()
+    {
+        $this->expectException(PersistenceManagerException::class);
+        $this->expectExceptionCode(1471630579);
+
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'getStorageByUid',
+        ], [], '', false);
+
+        $mockStorage = $this->getMockBuilder(ResourceStorage::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $mockStorage
+            ->expects($this->any())
+            ->method('hasFolder')
+            ->willReturn(false);
+
+        $mockFormPersistenceManager
+            ->expects($this->any())
+            ->method('getStorageByUid')
+            ->willReturn($mockStorage);
+
+        $input = '-1:/user_uploads/example.yaml';
+        $mockFormPersistenceManager->_call('getOrCreateFile', $input);
+    }
+
+    /**
+     * @test
+     */
+    public function getOrCreateFileThrowsExceptionIfWriteToStorageIsNotAllowed()
+    {
+        $this->expectException(PersistenceManagerException::class);
+        $this->expectExceptionCode(1471630580);
+
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'getStorageByUid',
+        ], [], '', false);
+
+        $mockStorage = $this->getMockBuilder(ResourceStorage::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $mockStorage
+            ->expects($this->any())
+            ->method('hasFolder')
+            ->willReturn(true);
+
+        $mockStorage
+            ->expects($this->any())
+            ->method('checkFileActionPermission')
+            ->willReturn(false);
+
+        $file = new File(['identifier' => '', 'mime_type' => ''], $mockStorage);
+        $mockStorage
+            ->expects($this->any())
+            ->method('getFile')
+            ->willReturn($file);
+
+        $mockFormPersistenceManager
+            ->expects($this->any())
+            ->method('getStorageByUid')
+            ->willReturn($mockStorage);
+
+        $input = '-1:/user_uploads/example.yaml';
+        $mockFormPersistenceManager->_call('getOrCreateFile', $input);
+    }
+
+    /**
+     * @test
+     */
+    public function getStorageByUidThrowsExceptionIfStorageNotExists()
+    {
+        $this->expectException(PersistenceManagerException::class);
+        $this->expectExceptionCode(1471630581);
+
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'dummy',
+        ], [], '', false);
+
+        $mockStorageRepository = $this->getMockBuilder(StorageRepository::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $mockStorageRepository
+            ->expects($this->any())
+            ->method('findByUid')
+            ->willReturn(null);
+
+        $mockFormPersistenceManager->_set('storageRepository', $mockStorageRepository);
+        $mockFormPersistenceManager->_call('getStorageByUid', -1);
+    }
+
+    /**
+     * @test
+     */
+    public function getStorageByUidThrowsExceptionIfStorageIsNotBrowsable()
+    {
+        $this->expectException(PersistenceManagerException::class);
+        $this->expectExceptionCode(1471630581);
+
+        $mockFormPersistenceManager = $this->getAccessibleMock(FormPersistenceManager::class, [
+            'dummy',
+        ], [], '', false);
+
+        $mockStorageRepository = $this->getMockBuilder(StorageRepository::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $mockStorage = $this->getMockBuilder(ResourceStorage::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $mockStorage
+            ->expects($this->any())
+            ->method('isBrowsable')
+            ->willReturn(false);
+
+        $mockStorageRepository
+            ->expects($this->any())
+            ->method('findByUid')
+            ->willReturn($mockStorage);
+
+        $mockFormPersistenceManager->_set('storageRepository', $mockStorageRepository);
+        $mockFormPersistenceManager->_call('getStorageByUid', -1);
+    }
+}
diff --git a/typo3/sysext/form/Tests/Unit/Mvc/ProcessingRuleTest.php b/typo3/sysext/form/Tests/Unit/Mvc/ProcessingRuleTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..714658aaa8f995fcb9b2018d0a29dcd2c67c7480
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Mvc/ProcessingRuleTest.php
@@ -0,0 +1,120 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Mvc\Configuration;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Error\Result;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
+use TYPO3\CMS\Extbase\Validation\Validator\ConjunctionValidator;
+use TYPO3\CMS\Form\Mvc\ProcessingRule;
+use TYPO3\CMS\Form\Tests\Unit\Mvc\Validation\Fixtures\TestValidator;
+
+/**
+ * Test case
+ */
+class ProcessingRuleTest extends UnitTestCase
+{
+
+    /**
+     * @var array A backup of registered singleton instances
+     */
+    protected $singletonInstances = [];
+
+    /**
+     * Set up
+     */
+    public function setUp()
+    {
+        $this->singletonInstances = GeneralUtility::getSingletonInstances();
+    }
+
+    /**
+     * Tear down
+     */
+    public function tearDown()
+    {
+        GeneralUtility::resetSingletonInstances($this->singletonInstances);
+        parent::tearDown();
+    }
+
+    /**
+     * @test
+     */
+    public function addValidatorAddValidator()
+    {
+        $mockProcessingRule = $this->getAccessibleMock(ProcessingRule::class, [
+            'dummy'
+        ], [], '', false);
+
+        $mockProcessingRule->_set('validator', new ConjunctionValidator([]));
+        $mockProcessingRule->addValidator(new TestValidator());
+        $validators = $mockProcessingRule->_get('validator')->getValidators();
+        $validators->rewind();
+        $this->assertInstanceOf(AbstractValidator::class, $validators->current());
+    }
+
+    /**
+     * @test
+     */
+    public function processNoPropertyMappingReturnsNotModifiedValue()
+    {
+        $objectMangerProphecy = $this->prophesize(ObjectManager::class);
+        GeneralUtility::setSingletonInstance(ObjectManager::class, $objectMangerProphecy->reveal());
+        $resultProphecy = $this->prophesize(Result::class);
+
+        $objectMangerProphecy
+            ->get(Result::class)
+            ->willReturn($resultProphecy->reveal());
+
+        $mockProcessingRule = $this->getAccessibleMock(ProcessingRule::class, [
+            'dummy'
+        ], [], '', false);
+
+        $mockProcessingRule->_set('dataType', null);
+        $mockProcessingRule->_set('processingMessages', $resultProphecy->reveal());
+        $mockProcessingRule->_set('validator', new ConjunctionValidator([]));
+
+        $input = 'someValue';
+        $this->assertSame($input, $mockProcessingRule->_call('process', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function processNoPropertyMappingAndHasErrorsIfValidatorContainsErrors()
+    {
+        $objectMangerProphecy = $this->prophesize(ObjectManager::class);
+        GeneralUtility::setSingletonInstance(ObjectManager::class, $objectMangerProphecy->reveal());
+
+        $objectMangerProphecy
+            ->get(Result::class)
+            ->willReturn(new Result);
+
+        $mockProcessingRule = $this->getAccessibleMock(ProcessingRule::class, [
+            'dummy'
+        ], [], '', true);
+
+        $mockProcessingRule->_set('dataType', null);
+        $mockProcessingRule->_set('validator', new ConjunctionValidator([]));
+        $mockProcessingRule->addValidator(new TestValidator());
+
+        $input = 'addError';
+        $mockProcessingRule->_call('process', $input);
+
+        $this->assertTrue($mockProcessingRule->_get('processingMessages')->hasErrors());
+    }
+}
diff --git a/typo3/sysext/form/Tests/Unit/Mvc/Validation/CountValidatorTest.php b/typo3/sysext/form/Tests/Unit/Mvc/Validation/CountValidatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..bcff4b5c87a8bb06068f8f77ce61caab8c78a9d1
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Mvc/Validation/CountValidatorTest.php
@@ -0,0 +1,120 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Mvc\Validation;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Form\Mvc\Validation\CountValidator;
+
+/**
+ * Test case
+ */
+class CountValidatorTest extends UnitTestCase
+{
+
+    /**
+     * @test
+     */
+    public function CountValidatorReturnsFalseIfInputItemsCountIsEqualToMaximum()
+    {
+        $options = ['minimum' => 1, 'maximum' => 2];
+        $validator = $this->getMockBuilder(CountValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->setConstructorArgs([$options])
+            ->getMock();
+
+        $input = [
+            'klaus',
+            'steve'
+        ];
+
+        $this->assertFalse($validator->validate($input)->hasErrors());
+    }
+
+    /**
+     * @test
+     */
+    public function CountValidatorReturnsFalseIfInputItemsCountIsEqualToMinimum()
+    {
+        $options = ['minimum' => 2, 'maximum' => 3];
+        $validator = $this->getMockBuilder(CountValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->setConstructorArgs([$options])
+            ->getMock();
+
+        $input = [
+            'klaus',
+            'steve'
+        ];
+
+        $this->assertFalse($validator->validate($input)->hasErrors());
+    }
+
+    /**
+     * @test
+     */
+    public function CountValidatorReturnsFalseIfInputItemsCountIsEqualToMinimumAndMaximum()
+    {
+        $options = ['minimum' => 2, 'maximum' => 2];
+        $validator = $this->getMockBuilder(CountValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->setConstructorArgs([$options])
+            ->getMock();
+
+        $input = [
+            'klaus',
+            'steve'
+        ];
+
+        $this->assertFalse($validator->validate($input)->hasErrors());
+    }
+
+    /**
+     * @test
+     */
+    public function CountValidatorReturnsTrueIfInputCountHasMoreItemsAsMaximumValue()
+    {
+        $options = ['minimum' => 1, 'maximum' => 2];
+        $validator = $this->getMockBuilder(CountValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->setConstructorArgs([$options])
+            ->getMock();
+
+        $input = [
+            'klaus',
+            'steve',
+            'francine'
+        ];
+
+        $this->assertTrue($validator->validate($input)->hasErrors());
+    }
+
+    /**
+     * @test
+     */
+    public function CountValidatorReturnsTrueIfInputCountHasLessItemsAsMinimumValue()
+    {
+        $options = ['minimum' => 2, 'maximum' => 3];
+        $validator = $this->getMockBuilder(CountValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->setConstructorArgs([$options])
+            ->getMock();
+
+        $input = [
+            'klaus',
+        ];
+
+        $this->assertTrue($validator->validate($input)->hasErrors());
+    }
+}
diff --git a/typo3/sysext/form/Tests/Unit/Mvc/Validation/EmptyValidatorTest.php b/typo3/sysext/form/Tests/Unit/Mvc/Validation/EmptyValidatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..fce017f58ec26d8f4eace57e5227091b987a8e32
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Mvc/Validation/EmptyValidatorTest.php
@@ -0,0 +1,123 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Mvc\Validation;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Form\Mvc\Validation\EmptyValidator;
+
+/**
+ * Test case
+ */
+class EmptyValidatorTest extends UnitTestCase
+{
+
+    /**
+     * @test
+     */
+    public function EmptyValidatorReturnsFalseIfInputIsEmptyString()
+    {
+        $validator = $this->getMockBuilder(EmptyValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->getMock();
+
+        $input = '';
+
+        $this->assertFalse($validator->validate($input)->hasErrors());
+    }
+
+    /**
+     * @test
+     */
+    public function EmptyValidatorReturnsFalseIfInputIsNull()
+    {
+        $validator = $this->getMockBuilder(EmptyValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->getMock();
+
+        $input = null;
+
+        $this->assertFalse($validator->validate($input)->hasErrors());
+    }
+
+    /**
+     * @test
+     */
+    public function EmptyValidatorReturnsFalseIfInputIsEmptyArray()
+    {
+        $validator = $this->getMockBuilder(EmptyValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->getMock();
+
+        $input = [];
+
+        $this->assertFalse($validator->validate($input)->hasErrors());
+    }
+
+    /**
+     * @test
+     */
+    public function EmptyValidatorReturnsFalseIfInputIsZero()
+    {
+        $validator = $this->getMockBuilder(EmptyValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->getMock();
+
+        $input = 0;
+
+        $this->assertFalse($validator->validate($input)->hasErrors());
+    }
+
+    /**
+     * @test
+     */
+    public function EmptyValidatorReturnsFalseIfInputIsZeroAsString()
+    {
+        $validator = $this->getMockBuilder(EmptyValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->getMock();
+
+        $input = '0';
+
+        $this->assertFalse($validator->validate($input)->hasErrors());
+    }
+
+    /**
+     * @test
+     */
+    public function EmptyValidatorReturnsTrueIfInputIsNonEmptyString()
+    {
+        $validator = $this->getMockBuilder(EmptyValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->getMock();
+
+        $input = 'hellö';
+
+        $this->assertTrue($validator->validate($input)->hasErrors());
+    }
+
+    /**
+     * @test
+     */
+    public function EmptyValidatorReturnsTrueIfInputIsNonEmptyArray()
+    {
+        $validator = $this->getMockBuilder(EmptyValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->getMock();
+
+        $input = ['hellö'];
+
+        $this->assertTrue($validator->validate($input)->hasErrors());
+    }
+}
diff --git a/typo3/sysext/form/Classes/Domain/Filter/DigitFilter.php b/typo3/sysext/form/Tests/Unit/Mvc/Validation/Fixtures/TestValidator.php
similarity index 54%
rename from typo3/sysext/form/Classes/Domain/Filter/DigitFilter.php
rename to typo3/sysext/form/Tests/Unit/Mvc/Validation/Fixtures/TestValidator.php
index 95d49c510d9326a99514ad8c2a27eaaa36b3c905..1ddc62cea40fc88b2a47ea90a6d05a0a7d8f5dac 100644
--- a/typo3/sysext/form/Classes/Domain/Filter/DigitFilter.php
+++ b/typo3/sysext/form/Tests/Unit/Mvc/Validation/Fixtures/TestValidator.php
@@ -1,5 +1,5 @@
 <?php
-namespace TYPO3\CMS\Form\Domain\Filter;
+namespace TYPO3\CMS\Form\Tests\Unit\Mvc\Validation\Fixtures;
 
 /*
  * This file is part of the TYPO3 CMS project.
@@ -14,21 +14,23 @@ namespace TYPO3\CMS\Form\Domain\Filter;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
+
 /**
- * Digit filter
+ * Validator for unit tetst
+ *
+ * @api
  */
-class DigitFilter extends AbstractFilter implements FilterInterface
+class TestValidator extends AbstractValidator
 {
     /**
-     * Return filtered value
-     * Remove all but digits
-     *
-     * @param string $value
-     * @return string
+     * @param mixed $value
+     * @return void
      */
-    public function filter($value)
+    public function isValid($value)
     {
-        $pattern = '/[^0-9]/';
-        return preg_replace($pattern, '', (string)$value);
+        if ($value === 'addError') {
+            $this->addError('Error', 1480201569);
+        }
     }
 }
diff --git a/typo3/sysext/form/Tests/Unit/Mvc/Validation/MimeTypeValidatorTest.php b/typo3/sysext/form/Tests/Unit/Mvc/Validation/MimeTypeValidatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ed234322b4c02f19ee68f6c587f3ac1f712c07d4
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Mvc/Validation/MimeTypeValidatorTest.php
@@ -0,0 +1,109 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Mvc\Validation;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Resource\File;
+use TYPO3\CMS\Core\Resource\ResourceStorage;
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Form\Mvc\Validation\Exception\InvalidValidationOptionsException;
+use TYPO3\CMS\Form\Mvc\Validation\MimeTypeValidator;
+
+/**
+ * Test case
+ */
+class MimeTypeValidatorTest extends UnitTestCase
+{
+
+    /**
+     * @test
+     */
+    public function MimeTypeValidatorThrowsExceptionIfAllowedMimeTypesOptionIsString()
+    {
+        $this->expectException(InvalidValidationOptionsException::class);
+        $this->expectExceptionCode(1471713296);
+
+        $options = ['allowedMimeTypes' => ''];
+        $validator = $this->getMockBuilder(MimeTypeValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->setConstructorArgs(['options' => $options])
+            ->getMock();
+
+        $validator->validate(true);
+    }
+
+    /**
+     * @test
+     */
+    public function MimeTypeValidatorThrowsExceptionIfAllowedMimeTypesOptionIsEmptyArray()
+    {
+        $this->expectException(InvalidValidationOptionsException::class);
+        $this->expectExceptionCode(1471713296);
+
+        $options = ['allowedMimeTypes' => []];
+        $validator = $this->getMockBuilder(MimeTypeValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->setConstructorArgs(['options' => $options])
+            ->getMock();
+
+        $validator->validate(true);
+    }
+
+    /**
+     * @test
+     */
+    public function MimeTypeValidatorReturnsTrueIfFileResourceIsNotAllowedMimeType()
+    {
+        $options = ['allowedMimeTypes' => ['image/jpeg']];
+        $validator = $this->getMockBuilder(MimeTypeValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->setConstructorArgs(['options' => $options])
+            ->getMock();
+
+        $mockedStorage = $this->getMockBuilder(ResourceStorage::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $file = new File(['identifier' => '/foo', 'mime_type' => 'image/png'], $mockedStorage);
+        $this->assertTrue($validator->validate($file)->hasErrors());
+    }
+
+    /**
+     * @test
+     */
+    public function MimeTypeValidatorReturnsFalseIfInputIsEmptyString()
+    {
+        $options = ['allowedMimeTypes' => ['fake']];
+        $validator = $this->getMockBuilder(MimeTypeValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->setConstructorArgs(['options' => $options])
+            ->getMock();
+
+        $this->assertFalse($validator->validate('')->hasErrors());
+    }
+
+    /**
+     * @test
+     */
+    public function MimeTypeValidatorReturnsTrueIfInputIsNoFileResource()
+    {
+        $options = ['allowedMimeTypes' => ['fake']];
+        $validator = $this->getMockBuilder(MimeTypeValidator::class)
+            ->setMethods(['translateErrorMessage'])
+            ->setConstructorArgs(['options' => $options])
+            ->getMock();
+
+        $this->assertTrue($validator->validate('string')->hasErrors());
+    }
+}
diff --git a/typo3/sysext/form/Tests/Unit/PostProcess/MailPostProcessorTest.php b/typo3/sysext/form/Tests/Unit/PostProcess/MailPostProcessorTest.php
deleted file mode 100644
index 510986f83dec40ec2576b51f5660137119ea9b08..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/PostProcess/MailPostProcessorTest.php
+++ /dev/null
@@ -1,100 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\PostProcess;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class MailPostProcessorTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
-{
-    /**
-     * @var \TYPO3\CMS\Form\PostProcess\MailPostProcessor
-     */
-    protected $mailPostProcessor;
-
-    /**
-     * Set up
-     *
-     * @return void
-     */
-    protected function setUp()
-    {
-        parent::setUp();
-        $this->mailPostProcessor = $this->getAccessibleMock(
-            \TYPO3\CMS\Form\PostProcess\MailPostProcessor::class,
-            ['__none'],
-            [],
-            '',
-            false
-        );
-    }
-
-    /**
-     * Data provider for filterValidEmailsReturnsOnlyValidAddresses
-     *
-     * @return array input string, expected return array
-     * @TODO: Add a umlaut domain test case
-     */
-    public function filterValidEmailsProvider()
-    {
-        return [
-            'empty string' => [
-                '',
-                [],
-            ],
-            'string not representing an email' => [
-                'notAnAddress',
-                [],
-            ],
-            'simple single valid address' => [
-                'someone@example.com',
-                [
-                    'someone@example.com',
-                ],
-            ],
-            'multiple valid simple addresses' => [
-                'someone@example.com, foo@bar.com',
-                [
-                    'someone@example.com',
-                    'foo@bar.com',
-                ],
-            ],
-            'multiple addresses with personal part' => [
-                'Foo <foo@example.com>, <bar@example.com>, "Foo, bar" <foo.bar@example.com>',
-                [
-                    'bar@example.com',
-                    'foo@example.com' => 'Foo',
-                    'foo.bar@example.com' => '"Foo, bar"',
-                ],
-            ],
-            'list with invalid addresses is filtered' => [
-                'invalid, @invalid, someone@example.com',
-                [
-                    'someone@example.com',
-                ],
-            ],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider filterValidEmailsProvider
-     */
-    public function filterValidEmailsReturnsOnlyValidAddresses($input, $expected)
-    {
-        $actualResult = $this->mailPostProcessor->_call('filterValidEmails', $input);
-        $this->assertEquals($expected, $actualResult);
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/PostProcess/PostProcessorTest.php b/typo3/sysext/form/Tests/Unit/PostProcess/PostProcessorTest.php
deleted file mode 100644
index 7429417e5746c3cc71b5dcc32ef7206b70510dbd..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/PostProcess/PostProcessorTest.php
+++ /dev/null
@@ -1,149 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\PostProcess;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use Prophecy\Argument;
-use TYPO3\CMS\Core\Tests\UnitTestCase;
-use TYPO3\CMS\Extbase\Object\ObjectManager;
-use TYPO3\CMS\Form\Domain\Model\Element;
-use TYPO3\CMS\Form\Mvc\Controller\ControllerContext;
-use TYPO3\CMS\Form\PostProcess\PostProcessor;
-use TYPO3\CMS\Form\Tests\Unit\Fixtures\PostProcessorWithFormPrefixFixture;
-use TYPO3\CMS\Form\Tests\Unit\Fixtures\PostProcessorWithoutFormPrefixFixture;
-use TYPO3\CMS\Form\Tests\Unit\Fixtures\PostProcessorWithoutInterfaceFixture;
-
-/**
- * Testcase for PostProcessor
- */
-class PostProcessorTest extends UnitTestCase
-{
-    /**
-     * @var array A backup of registered singleton instances
-     */
-    protected $singletonInstances = [];
-
-    /**
-     * @var Element|\Prophecy\Prophecy\ObjectProphecy
-     */
-    protected $elementProphecy;
-
-    /**
-     * @var ObjectManager|\Prophecy\Prophecy\ObjectProphecy
-     */
-    protected $objectManagerProphecy;
-
-    /**
-     * @var ControllerContext|\Prophecy\Prophecy\ObjectProphecy
-     */
-    protected $controllerContextProphecy;
-
-    /**
-     * Sets up this test case.
-     */
-    protected function setUp()
-    {
-        parent::setUp();
-        $this->elementProphecy = $this->prophesize(Element::class);
-        $this->objectManagerProphecy = $this->prophesize(ObjectManager::class);
-        $this->controllerContextProphecy = $this->prophesize(ControllerContext::class);
-    }
-
-    /**
-     * Tears down this test case.
-     */
-    protected function tearDown()
-    {
-        parent::tearDown();
-        unset($this->elementProphecy);
-        unset($this->objectManagerProphecy);
-        unset($this->controllerContextProphecy);
-    }
-
-    /**
-     * @test
-     */
-    public function processFindsClassSpecifiedByTypoScriptWithoutFormPrefix()
-    {
-        $typoScript = [
-            10 => $this->getUniqueId('postprocess'),
-            20 => PostProcessorWithoutFormPrefixFixture::class
-        ];
-
-        $this->objectManagerProphecy
-            ->get(Argument::cetera())
-            ->will(function ($arguments) {
-                return new $arguments[0]($arguments[1], $arguments[2]);
-            });
-
-        $subject = $this->createSubject($typoScript);
-        $this->assertEquals('processedWithoutPrefix', $subject->process());
-    }
-
-    /**
-     * @test
-     */
-    public function processFindsClassSpecifiedByTypoScriptWithFormPrefix()
-    {
-        $typoScript = [
-            10 => $this->getUniqueId('postprocess'),
-            20 => PostProcessorWithFormPrefixFixture::class
-        ];
-
-        $this->objectManagerProphecy
-            ->get(Argument::cetera())
-            ->will(function ($arguments) {
-                return new $arguments[0]($arguments[1], $arguments[2]);
-            });
-
-        $subject = $this->createSubject($typoScript);
-        $this->assertEquals('processedWithPrefix', $subject->process());
-    }
-
-    /**
-     * @test
-     */
-    public function processReturnsEmptyStringIfSpecifiedPostProcessorDoesNotImplementTheInterface()
-    {
-        $typoScript = [
-            10 => $this->getUniqueId('postprocess'),
-            20 => PostProcessorWithoutInterfaceFixture::class
-        ];
-
-        $this->objectManagerProphecy
-            ->get(Argument::cetera())
-            ->will(function ($arguments) {
-                return new $arguments[0]($arguments[1], $arguments[2]);
-            });
-
-        $subject = $this->createSubject($typoScript);
-        $this->assertEquals('', $subject->process());
-    }
-
-    /**
-     * @param array $typoScript
-     * @return PostProcessor|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface
-     */
-    protected function createSubject(array $typoScript)
-    {
-        $subject = $this->getAccessibleMock(
-            PostProcessor::class,
-            ['__none'],
-            [$this->elementProphecy->reveal(), $typoScript]
-        );
-        $subject->_set('controllerContext', $this->controllerContextProphecy->reveal());
-        $subject->_set('objectManager', $this->objectManagerProphecy->reveal());
-        return $subject;
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Utility/ArrayUtilityTest.php b/typo3/sysext/form/Tests/Unit/Utility/ArrayUtilityTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9fbdc4fa13566d8d3a85db93e29fe423c1c00e1b
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/Utility/ArrayUtilityTest.php
@@ -0,0 +1,251 @@
+<?php
+namespace TYPO3\CMS\Form\Tests\Unit\Utility;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Form\Domain\Exception\TypeDefinitionNotValidException;
+use TYPO3\CMS\Form\Utility\ArrayUtility;
+
+/**
+ * Test case
+ */
+class ArrayUtilityTest extends UnitTestCase
+{
+
+    /**
+     * @test
+     */
+    public function assertAllArrayKeysAreValidThrowsExceptionOnNotAllowedArrayKeys()
+    {
+        $this->expectException(TypeDefinitionNotValidException::class);
+        $this->expectExceptionCode(1325697085);
+
+        $arrayToTest = [
+            'roger' => '',
+            'francine' => '',
+            'stan' => '',
+        ];
+
+        $allowedArrayKeys = [
+            'roger',
+            'francine',
+        ];
+
+        ArrayUtility::assertAllArrayKeysAreValid($arrayToTest, $allowedArrayKeys);
+    }
+
+    /**
+     * @test
+     */
+    public function assertAllArrayKeysAreValidReturnsNullOnAllowedArrayKeys()
+    {
+        $arrayToTest = [
+            'roger' => '',
+            'francine' => '',
+            'stan' => '',
+        ];
+
+        $allowedArrayKeys = [
+            'roger',
+            'francine',
+            'stan',
+        ];
+
+        $this->assertNull(ArrayUtility::assertAllArrayKeysAreValid($arrayToTest, $allowedArrayKeys));
+    }
+
+    /**
+     * @test
+     */
+    public function sortNumericArrayKeysRecursiveExpectSorting()
+    {
+        $input = [
+            20 => 'b',
+            10 => 'a',
+            40 => 'd',
+            30 => 'c',
+            50 => [
+                20 => 'a',
+                10 => 'b',
+            ],
+        ];
+
+        $expected = [
+            10 => 'a',
+            20 => 'b',
+            30 => 'c',
+            40 => 'd',
+            50 => [
+                10 => 'b',
+                20 => 'a',
+            ],
+        ];
+
+        $this->assertSame($expected, ArrayUtility::sortNumericArrayKeysRecursive($input));
+    }
+
+    /**
+     * @test
+     */
+    public function sortNumericArrayKeysRecursiveExpectNoSorting()
+    {
+        $input = [
+            'b' => 'b',
+            10 => 'a',
+            40 => 'd',
+            30 => 'c',
+        ];
+
+        $expected = [
+            'b' => 'b',
+            10 => 'a',
+            40 => 'd',
+            30 => 'c',
+        ];
+
+        $this->assertSame($expected, ArrayUtility::sortNumericArrayKeysRecursive($input));
+    }
+
+    /**
+     * @test
+     */
+    public function reIndexNumericArrayKeysRecursiveExpectReindexing()
+    {
+        $input = [
+            20 => 'b',
+            10 => 'a',
+            40 => 'd',
+            30 => 'c',
+            50 => [
+                20 => 'a',
+                10 => 'b',
+            ],
+        ];
+
+        $expected = [
+            0 => 'b',
+            1 => 'a',
+            2 => 'd',
+            3 => 'c',
+            4 => [
+                0 => 'a',
+                1 => 'b',
+            ],
+        ];
+
+        $this->assertSame($expected, ArrayUtility::reIndexNumericArrayKeysRecursive($input));
+    }
+
+    /**
+     * @test
+     */
+    public function reIndexNumericArrayKeysRecursiveExpectNoReindexing()
+    {
+        $input = [
+            'a' => 'b',
+            10 => 'a',
+            40 => 'd',
+            30 => 'c',
+            50 => [
+                20 => 'a',
+                10 => 'b',
+            ],
+        ];
+
+        $expected = [
+            'a' => 'b',
+            10 => 'a',
+            40 => 'd',
+            30 => 'c',
+            50 => [
+                0 => 'a',
+                1 => 'b',
+            ],
+        ];
+
+        $this->assertSame($expected, ArrayUtility::reIndexNumericArrayKeysRecursive($input));
+    }
+
+    /**
+     * @test
+     */
+    public function removeNullValuesRecursiveExpectRemoval()
+    {
+        $input = [
+            'a' => 'a',
+            'b' => [
+                'c' => null,
+                'd' => 'd',
+            ],
+        ];
+
+        $expected = [
+            'a' => 'a',
+            'b' => [
+                'd' => 'd',
+            ],
+        ];
+
+        $this->assertSame($expected, ArrayUtility::removeNullValuesRecursive($input));
+    }
+
+    /**
+     * @test
+     */
+    public function stripTagsFromValuesRecursiveExpectRemoval()
+    {
+        $input = [
+            'a' => 'a',
+            'b' => [
+                'c' => '<b>i am evil</b>',
+                'd' => 'd',
+            ],
+        ];
+
+        $expected = [
+            'a' => 'a',
+            'b' => [
+                'c' => 'i am evil',
+                'd' => 'd',
+            ],
+        ];
+
+        $this->assertSame($expected, ArrayUtility::stripTagsFromValuesRecursive($input));
+    }
+
+    /**
+     * @test
+     */
+    public function convertBooleanStringsToBooleanRecursiveExpectConverting()
+    {
+        $input = [
+            'a' => 'a',
+            'b' => [
+                'c' => 'true',
+                'd' => 'd',
+            ],
+        ];
+
+        $expected = [
+            'a' => 'a',
+            'b' => [
+                'c' => true,
+                'd' => 'd',
+            ],
+        ];
+
+        $this->assertSame($expected, ArrayUtility::convertBooleanStringsToBooleanRecursive($input));
+    }
+}
diff --git a/typo3/sysext/form/Tests/Unit/Utility/TypoScriptToJsonConverterTest.php b/typo3/sysext/form/Tests/Unit/Utility/TypoScriptToJsonConverterTest.php
deleted file mode 100644
index 3b641ba061162fd046a6708a24e0090a8e77b925..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Utility/TypoScriptToJsonConverterTest.php
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Utility;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Tests\AccessibleObjectInterface;
-use TYPO3\CMS\Core\Tests\UnitTestCase;
-use TYPO3\CMS\Form\Domain\Model\Json\FormJsonElement;
-use TYPO3\CMS\Form\Utility\TypoScriptToJsonConverter;
-
-/**
- * Test case for \TYPO3\CMS\Form\Utility\TypoScriptToJsonConverter
- */
-class TypoScriptToJsonConverterTest extends UnitTestCase
-{
-    /**
-     * Checks if calling protected method getChildElementsByIntegerKey with different data
-     * calls the addMethod in the mocked FormJsonElement for an expected method count.
-     *
-     * @dataProvider getChildElementsByIntegerKeyCallsAddElementDataProvider
-     * @param array $typoScript
-     * @param int $methodCount
-     * @test
-     */
-    public function getChildElementsByIntegerKeyCallsAddElement(array $typoScript, $methodCount)
-    {
-        /** @var FormJsonElement|\PHPUnit_Framework_MockObject_MockObject $mockSubject */
-        $parentElement = $this->getMockBuilder(FormJsonElement::class)
-            ->setMethods(['addElement'])
-            ->getMock();
-        // check if method gets called exactly X times
-        $parentElement->expects($this->exactly($methodCount))->method('addElement');
-
-        /** @var TypoScriptToJsonConverter|\PHPUnit_Framework_MockObject_MockObject|AccessibleObjectInterface $subjectAccessible */
-        $accessibleSubject = $this->getAccessibleMock(TypoScriptToJsonConverter::class, ['dummy']);
-        $accessibleSubject->_call('getChildElementsByIntegerKey', $parentElement, $typoScript);
-    }
-
-    /**
-     * Data provider for test method getChildElementsByIntegerKeyCallsAddElement.
-     *
-     * @return array
-     */
-    public function getChildElementsByIntegerKeyCallsAddElementDataProvider()
-    {
-        return [
-            [
-                'typoscript' => [
-                    'prefix' => 'tx_form',
-                    'confirmation' => '1',
-                    'postProcessor.' => [
-                        '1' => 'mail',
-                        '1.' => [
-                            'recipientEmail' => '',
-                            'senderEmail' => '',
-                        ],
-                    ],
-                    '10' => 'FILEUPLOAD',
-                    '10.' => [
-                        'name' => 'foo',
-                        'type' => 'file',
-                        'label.' => [
-                            'value' => 'Edit this label',
-                        ],
-                    ],
-                ],
-                1
-            ],
-        ];
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/AbstractValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/AbstractValidatorTest.php
deleted file mode 100644
index b934c76de3e511f892c96a65c1185c574ad1652f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/AbstractValidatorTest.php
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Form\Domain\Validator\AbstractValidator;
-use TYPO3\CMS\Form\Utility\FormUtility;
-
-/**
- * Test case
- */
-abstract class AbstractValidatorTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
-{
-    /**
-     * Must be filled with subject class name
-     * in specific test implementation.
-     *
-     * @var string
-     */
-    protected $subjectClassName = null;
-
-    /**
-     * @param array $options
-     * @return AbstractValidator|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected function createSubject(array $options)
-    {
-        /** @var AbstractValidator $subject */
-        $subject = $this->getMockBuilder($this->subjectClassName)
-            ->setMethods(['getLocalLanguageLabel', 'humanReadableDateFormat'])
-            ->setConstructorArgs(['options' => $options])
-            ->getMock();
-
-        /** @var FormUtility $formUtilityMock */
-        $formUtilityMock = $this->createMock(FormUtility::class);
-        $subject->setFormUtility($formUtilityMock);
-
-        return $subject;
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/AlphabeticValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/AlphabeticValidatorTest.php
deleted file mode 100644
index 0fd578f3490e13e76d3b8b7bc5240a963433ee60..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/AlphabeticValidatorTest.php
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class AlphabeticValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\AlphabeticValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validDataProviderWithoutWhitespace()
-    {
-        return [
-            'ascii without spaces' => ['thisismyinput'],
-            'accents without spaces' => ['éóéàèò'],
-            'umlauts without spaces' => ['üöä'],
-            'empty string' => ['']
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function validDataProviderWithWhitespace()
-    {
-        return [
-            'ascii with spaces' => ['This is my input'],
-            'accents with spaces' => ['Sigur Rós'],
-            'umlauts with spaces' => ['Hürriyet Daily News'],
-            'space' => [' '],
-            'empty string' => ['']
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidDataProviderWithoutWhitespace()
-    {
-        return [
-            'ascii with dash' => ['my-name'],
-            'accents with underscore' => ['Sigur_Rós'],
-            'umlauts with periods' => ['Hürriyet.Daily.News'],
-            'space' => [' '],
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidDataProviderWithWhitespace()
-    {
-        return [
-            'ascii with spaces and dashes' => ['This is my-name'],
-            'accents with spaces and underscores' => ['Listen to Sigur_Rós_Band'],
-            'umlauts with spaces and periods' => ['Go get the Hürriyet.Daily.News']
-        ];
-    }
-
-    /**
-     * @param string $input
-     * @test
-     * @dataProvider validDataProviderWithoutWhitespace
-     */
-    public function validateForValidInputWithoutAllowedWhitespaceHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-
-    /**
-     * @param string $input
-     * @test
-     * @dataProvider validDataProviderWithWhitespace
-     */
-    public function validateForValidInputWithWhitespaceAllowedHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error'), 'allowWhiteSpace' => true];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-
-    /**
-     * @param string $input
-     * @test
-     * @dataProvider invalidDataProviderWithoutWhitespace
-     */
-    public function validateForInvalidInputWithoutAllowedWhitespaceHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-
-    /**
-     * @param string $input
-     * @test
-     * @dataProvider invalidDataProviderWithWhitespace
-     */
-    public function validateForInvalidInputWithWhitespaceAllowedHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error'), 'allowWhiteSpace' => true];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/AlphanumericValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/AlphanumericValidatorTest.php
deleted file mode 100644
index 697c8b33187c55c75e8ea84a93d4f3aa2127fe91..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/AlphanumericValidatorTest.php
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class AlphanumericValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\AlphanumericValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validDataProviderWithoutWhitespace()
-    {
-        return [
-            'ascii without spaces' => ['thisismyinput4711'],
-            'accents without spaces' => ['éóéàèò4711'],
-            'umlauts without spaces' => ['üöä4711'],
-            'empty string' => ['']
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function validDataProviderWithWhitespace()
-    {
-        return [
-            'ascii with spaces' => ['This is my input 4711'],
-            'accents with spaces' => ['Sigur Rós 4711'],
-            'umlauts with spaces' => ['Hürriyet Daily News 4711'],
-            'space' => [' '],
-            'empty string' => ['']
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidDataProviderWithoutWhitespace()
-    {
-        return [
-            'ascii with dash' => ['my-name-4711'],
-            'accents with underscore' => ['Sigur_Rós_4711'],
-            'umlauts with periods' => ['Hürriyet.Daily.News.4711'],
-            'space' => [' '],
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidDataProviderWithWhitespace()
-    {
-        return [
-            'ascii with spaces and dashes' => ['This is my-name 4711'],
-            'accents with spaces and underscores' => ['Listen to Sigur_Rós_Band 4711'],
-            'umlauts with spaces and periods' => ['Go get the Hürriyet.Daily.News 4711']
-        ];
-    }
-
-    /**
-     * @param string $input
-     * @test
-     * @dataProvider validDataProviderWithoutWhitespace
-     */
-    public function validateForValidInputWithoutAllowedWhitespaceHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-
-    /**
-     * @param string $input
-     * @test
-     * @dataProvider validDataProviderWithWhitespace
-     */
-    public function validateForValidInputWithAllowedWhitespaceHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error'), 'allowWhiteSpace' => true];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-
-    /**
-     * @param string $input
-     * @test
-     * @dataProvider invalidDataProviderWithoutWhitespace
-     */
-    public function validateForInvalidInputWithoutAllowedWhitespaceHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-
-    /**
-     * @param string $input
-     * @test
-     * @dataProvider invalidDataProviderWithWhitespace
-     */
-    public function validateForInvalidInputWithAllowedWhitespaceHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error'), 'allowWhiteSpace' => true];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/BetweenValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/BetweenValidatorTest.php
deleted file mode 100644
index a641096f5854b72212c4f6b86d61920a8a7c2845..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/BetweenValidatorTest.php
+++ /dev/null
@@ -1,146 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class BetweenValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\BetweenValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validNonInclusiveDataProvider()
-    {
-        return [
-            '3 < 5 < 7'      => [[3, 5, 7]],
-            '0 < 10 < 20'    => [[0, 10, 20]],
-            '-10 < 0 < 10'   => [[-10, 0, 10]],
-            '-20 < -10 < 0'  => [[-20, -10, 0]],
-            '1 < 2 < 3'      => [[1, 2, 3]],
-            '1 < 1.01 < 1.1' => [[1, 1.01, 1.1]],
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidNonInclusiveDataProvider()
-    {
-        return [
-            '1 < 1 < 2'                 => [[1, 1, 2]],
-            '1 < 2 < 2'                 => [[1, 2, 2]],
-            '1.1 < 1.1 < 1.2'           => [[1.1, 1.1, 1.2]],
-            '1.1 < 1.2 < 1.2'           => [[1.1, 1.2, 1.2]],
-            '-10.1234 < -10.12340 < 10' => [[-10.1234, -10.12340, 10]],
-            '100 < 0 < -100'            => [[100, 0, -100]]
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function validInclusiveDataProvider()
-    {
-        return [
-            '1 ≤ 1 ≤ 1'                 => [[1, 1, 1]],
-            '-10.1234 ≤ -10.12340 ≤ 10' => [[-10.1234, -10.12340, 10]],
-            '-10.1234 ≤ -10 ≤ 10'       => [[-10.1234, -10.12340, 10]],
-        ];
-    }
-
-    public function invalidInclusiveDataProvider()
-    {
-        return [
-            '-10.1234 ≤ -10.12345 ≤ 10' => [[-10.1234, -10.12345, 10]],
-            '100 ≤ 0 ≤ -100'            => [[100, 0, -100]]
-        ];
-    }
-
-    /**
-     * @param array $input
-     * @test
-     * @dataProvider validNonInclusiveDataProvider
-     */
-    public function validateWithValidInputAndWithoutInclusiveHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['minimum'] = $input[0];
-        $options['maximum'] = $input[2];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-
-    /**
-     * @param array $input
-     * @test
-     * @dataProvider validInclusiveDataProvider
-     */
-    public function validateWithValidInputAndWithInclusiveHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['minimum'] = $input[0];
-        $options['maximum'] = $input[2];
-        $options['inclusive'] = true;
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-
-    /**
-     * @param array $input
-     * @test
-     * @dataProvider invalidNonInclusiveDataProvider
-     */
-    public function validateWithInvalidInputAndWithoutInclusiveHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['minimum'] = $input[0];
-        $options['maximum'] = $input[2];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-
-    /**
-     * @param array $input
-     * @test
-     * @dataProvider invalidInclusiveDataProvider
-     */
-    public function validateWithInvalidInputAndWithInclusiveHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['minimum'] = $input[0];
-        $options['maximum'] = $input[2];
-        $options['inclusive'] = true;
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/DateValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/DateValidatorTest.php
deleted file mode 100644
index 38df7a6cd472f2e7e8e90e1ca041c07789df8448..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/DateValidatorTest.php
+++ /dev/null
@@ -1,86 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class DateValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\DateValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validDateProvider()
-    {
-        return [
-            '28-03-2012' => [['%e-%m-%Y', '28-03-2012']],
-            '8-03-2012'  => [['%e-%m-%Y', '8-03-2012']],
-            '29-02-2012' => [['%d-%m-%Y', '29-02-2012']]
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidDateProvider()
-    {
-        return [
-            '32-03-2012' => [['%d-%m-%Y', '32-03-2012']],
-            '31-13-2012' => [['%d-%m-%Y', '31-13-2012']],
-            '29-02-2011' => [['%d-%m-%Y', '29-02-2011']]
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validDateProvider
-     * @param array $input
-     */
-    public function validateForValidInputHasEmptyErrorResult(array $input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['format'] = $input[0];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidDateProvider
-     * @param array $input
-     */
-    public function validateForInvalidInputHasNotEmptyErrorResult(array $input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['format'] = $input[0];
-        $subject = $this->createSubject($options);
-
-        $subject->expects($this->once())
-            ->method('humanReadableDateFormat')
-            ->willReturnArgument(0);
-
-        $this->assertNotEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/DigitValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/DigitValidatorTest.php
deleted file mode 100644
index b4973e2aa9cee5ff3509c6e044c5cdd097584f4b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/DigitValidatorTest.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class DigitValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\DigitValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validDigitProvider()
-    {
-        return [
-            'stringified integer'                    => ['2012'],
-            'stringified integer with leading zeros' => ['0002'],
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidDigitProvider()
-    {
-        return [
-            'stringified float'      => ['0.2012'],
-            'stringified scientific' => ['1.9E+11']
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validDigitProvider
-     */
-    public function validateForValidInputHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidDigitProvider
-     */
-    public function validateForInvalidInputHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/EmailValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/EmailValidatorTest.php
deleted file mode 100644
index 9eea1514afdda1b4e412706d923b86ec5df49e1b..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/EmailValidatorTest.php
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class EmailValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\EmailValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validEmailProvider()
-    {
-        return [
-            'a@b.de' => ['a@b.de'],
-            'somebody@mymac.local' => ['somebody@mymac.local'],
-            'empty value' => [''],
-            'unexpected value' => [[]],
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidEmailProvider()
-    {
-        return [
-            'myemail@' => ['myemail@'],
-            'myemail' => ['myemail'],
-            'somebody@localhost' => ['somebody@localhost'],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validEmailProvider
-     */
-    public function validateForValidInputHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidEmailProvider
-     */
-    public function validateForInvalidInputHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/EqualsValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/EqualsValidatorTest.php
deleted file mode 100644
index 1baee2ebc077595b1606ae22321dec784652519a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/EqualsValidatorTest.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class EqualsValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\EqualsValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validPairProvider()
-    {
-        return [
-            'something === something' => [['something', 'something']],
-            '4 === 4'                 => [[4, 4]]
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidPairProvider()
-    {
-        return [
-            'somethingElse !== something' => [['somethingElse', 'something']],
-            '4 !== 3'                     => [[4, 3]]
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validPairProvider
-     */
-    public function validateForValidInputHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['field'] = uniqid('field');
-        $subject = $this->createSubject($options);
-        $subject->setRawArgument([$options['field'] => $input[0]]);
-
-        $this->assertEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidPairProvider
-     */
-    public function validateForInvalidInputHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['field'] = uniqid('field');
-        $subject = $this->createSubject($options);
-        $subject->setRawArgument([$options['field'] => $input[0]]);
-
-        $this->assertNotEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/FileAllowedTypesValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/FileAllowedTypesValidatorTest.php
deleted file mode 100644
index 776bfba43ff067cc591bf480422d3146ec03f45f..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/FileAllowedTypesValidatorTest.php
+++ /dev/null
@@ -1,114 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class FileAllowedTypesValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\FileAllowedTypesValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validTypesProvider()
-    {
-        return [
-            'pdf in (pdf)' => [
-                'application/pdf',
-                [
-                    'type' => 'application/pdf',
-                ],
-            ],
-            'pdf in (pdf, json)' => [
-                'application/pdf, application/json',
-                [
-                    'type' => 'application/pdf',
-                ],
-            ],
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidTypesProvider()
-    {
-        return [
-            'xml in (pdf, json)' => [
-                'application/pdf, application/json',
-                [
-                    'type' => 'application/xml',
-                ],
-            ],
-            'xml in (pdf)' => [
-                'application/pdf',
-                [
-                    'type' => 'application/xml',
-                ],
-            ],
-            'empty mimetype' => [
-                'application/pdf, application/json',
-                [
-                    'type' => '',
-                ],
-            ],
-            'empty value' => [
-                'application/pdf, application/json',
-                '',
-            ],
-        ];
-    }
-
-    /**
-     * @test
-     * @param string $types
-     * @param array $value
-     * @dataProvider validTypesProvider
-     */
-    public function validateForValidInputHasEmptyErrorResult($types, $value)
-    {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-            'types' => $types,
-        ];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty($subject->validate($value)->getErrors());
-    }
-
-    /**
-     * @test
-     * @param string $types
-     * @param array $value
-     * @dataProvider invalidTypesProvider
-     */
-    public function validateForInvalidInputHasNotEmptyErrorResult($types, $value)
-    {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-            'types' => $types,
-        ];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty($subject->validate($value)->getErrors());
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/FileMaximumSizeValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/FileMaximumSizeValidatorTest.php
deleted file mode 100644
index 5dff12f007436ca2e445a6dd8bc5949233435493..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/FileMaximumSizeValidatorTest.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class FileMaximumSizeValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\FileMaximumSizeValidator::class;
-
-    protected function setUp()
-    {
-        $this->markTestSkipped('validate() instead of isValid() needs to be used');
-    }
-
-    public function validSizesProvider()
-    {
-        return [
-            '11B for max. 12B' => [[12, 11]],
-            '12B for max. 12B' => [[12, 12]]
-        ];
-    }
-
-    public function invalidSizesProvider()
-    {
-        return [
-            '12B for max. 11B' => [[11, 12]]
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validSizesProvider
-     */
-    public function validateForValidInputHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['maximum'] = $input[0];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-
-    /**
-     * @test
-     * @dataProvider inValidSizesProvider
-     */
-    public function validateForInvalidInputHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['maximum'] = $input[0];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/FileMinimumSizeValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/FileMinimumSizeValidatorTest.php
deleted file mode 100644
index 7b50869bcd554c89ad4fcf91bd0c8eaf639e936c..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/FileMinimumSizeValidatorTest.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class FileMinimumSizeValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\FileMinimumSizeValidator::class;
-
-    protected function setUp()
-    {
-        $this->markTestSkipped('validate() instead of isValid() needs to be used');
-    }
-
-    public function validSizesProvider()
-    {
-        return [
-            '12B for min. 11B' => [[11, 12]],
-            '12B for min. 12B' => [[12, 12]]
-        ];
-    }
-
-    public function invalidSizesProvider()
-    {
-        return [
-            '11B for min. 12B' => [[12, 11]]
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validSizesProvider
-     */
-    public function validateForValidInputHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['minimum'] = $input[0];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidSizesProvider
-     */
-    public function validateForInvalidInputHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['minimum'] = $input[0];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/FloatValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/FloatValidatorTest.php
deleted file mode 100644
index 5cfc288cb42e89ed7adb9502875d52322b63ca35..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/FloatValidatorTest.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class FloatValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\FloatValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validFloatProvider()
-    {
-        return [
-            '12.1 for en_US locale' => [
-                '12.1',
-                'en_US.utf8',
-            ],
-            '12,1 for de_DE locale' => [
-                '12,1',
-                'de_DE.utf8',
-            ],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validFloatProvider
-     */
-    public function validateForValidInputHasEmptyErrorResult($inputValue, $locale)
-    {
-        try {
-            $this->setLocale(LC_NUMERIC, $locale);
-        } catch (\PHPUnit_Framework_Exception $e) {
-            $this->markTestSkipped('Locale ' . $locale . ' is not available.');
-        }
-
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($inputValue)->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/GreaterThanValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/GreaterThanValidatorTest.php
deleted file mode 100644
index a30d1168d87479e6644bc16e5fe412be15c10a87..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/GreaterThanValidatorTest.php
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class GreaterThanValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\GreaterThanValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validNumberProvider()
-    {
-        return [
-            '13 > 12' => [[12, 13]],
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidNumberProvider()
-    {
-        return [
-            '(int)12.1 > 12'  => [[12, 12.1]],
-            '(int)12 > 12'    => [[12, 12]],
-            '(int)11.99 > 12' => [[12, 11.99]]
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validNumberProvider
-     */
-    public function validateForValidInputHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['minimum'] = $input[0];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidNumberProvider
-     */
-    public function validateForInvalidInputHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['minimum'] = $input[0];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/InArrayValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/InArrayValidatorTest.php
deleted file mode 100644
index 40a8be95ad19e12c97b285112657d73d8dd2b775..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/InArrayValidatorTest.php
+++ /dev/null
@@ -1,800 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-use TYPO3\CMS\Form\Domain\Validator\InArrayValidator;
-
-/**
- * Test case
- */
-class InArrayValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = InArrayValidator::class;
-
-    /**
-     * used for tests with valid input
-     * will result in no errors returned
-     *
-     * @return array
-     */
-    public function validArrayForStringConfigurationProvider()
-    {
-        return [
-            '12 in (12, 13, 14)' => [
-                '12',
-                '12,13,14',
-            ],
-            '1 in (5, 3234, oOIUoi8, 3434, 343, 34, 3, 1, 333434, 1234, ssd, ysdfsa)' => [
-                '1',
-                '5,3234,oOIUoi8,3434,343,34,3,1,333434,1234,ssd,ysdfsa',
-            ],
-            'Pizza in (Pizza, Lasange, Strogonvo)' => [
-                'Pizza',
-                'Pizza,Lasange,Strogonvo',
-            ],
-            'Rißtissen in (Rißtissen, Überligen, Karlsruhe)' => [
-                'Rißtissen',
-                'Rißtissen,Überligen,Karlsruhe',
-            ],
-
-            '[12 and 14] in (12, 13, 14)' => [
-                ['12', '14'],
-                '12,13,14',
-            ],
-            '[1 and ssd] in (5, 3234, oOIUoi8, 3434, 343, 34, 3, 1, 333434, 1234, ssd, ysdfsa)' => [
-                ['1', 'ssd'],
-                '5,3234,oOIUoi8,3434,343,34,3,1,333434,1234,ssd,ysdfsa',
-            ],
-            '[Pizza and Strogonvo] in (Pizza, Lasange, Strogonvo)' => [
-                ['Pizza', 'Strogonvo'],
-                'Pizza,Lasange,Strogonvo',
-            ],
-            '[Rißtissen and Karlsruhe] in (Rißtissen, Überligen, Karlsruhe)' => [
-                ['Rißtissen', 'Karlsruhe'],
-                'Rißtissen,Überligen,Karlsruhe',
-            ],
-        ];
-    }
-
-    /**
-     * used for tests with valid input
-     * will result in no errors returned
-     *
-     * @return array
-     */
-    public function validArrayForArrayConfigurationProvider()
-    {
-        return [
-            '12 in [12, 13, 14]' => [
-                '12',
-                ['12', '13', '14'],
-            ],
-            '1 in [5, 3234, oOIUoi8, 3434, 343, 34, 3, 1, 333434, 1234, ssd, ysdfsa]' => [
-                '1',
-                ['5', '3234', 'oOIUoi8', '3434', '343', '34', '3', '1', '333434', '1234', 'ssd', 'ysdfsa'],
-            ],
-            'Pizza in [Pizza, Lasange, Strogonvo]' => [
-                ['Pizza', 'Strogonvo'],
-                ['Pizza', 'Lasange', 'Strogonvo'],
-            ],
-            'Rißtissen in [Rißtissen, Überligen, Karlsruhe]' => [
-                ['Rißtissen', 'Karlsruhe'],
-                ['Rißtissen', 'Überligen', 'Karlsruhe'],
-            ],
-
-            '[12 and 14] in [12, 13, 14]' => [
-                ['12', '14'],
-                ['12', '13', '14'],
-            ],
-            '[1 and ssd] in [5, 3234, oOIUoi8, 3434, 343, 34, 3, 1, 333434, 1234, ssd, ysdfsa]' => [
-                ['1', 'ssd'],
-                ['5', '3234', 'oOIUoi8', '3434', '343', '34', '3', '1', '333434', '1234', 'ssd', 'ysdfsa'],
-            ],
-            '[Pizza and Strogonvo] in [Pizza, Lasange, Strogonvo]' => [
-                'Pizza',
-                ['Pizza', 'Lasange', 'Strogonvo'],
-            ],
-            '[Rißtissen and Karlsruhe] in [Rißtissen, Überligen, Karlsruhe]' => [
-                'Rißtissen',
-                ['Rißtissen', 'Überligen', 'Karlsruhe'],
-            ],
-        ];
-    }
-
-    /**
-     * used for test with invalid input
-     * will result in errors returned
-     *
-     * @return array
-     */
-    public function invalidArrayForStringConfigurationProvider()
-    {
-        return [
-            '12 in (11, 13, 14)' => [
-                '12',
-                '11,13,14',
-            ],
-            '1 in (5, 3234, oOIUoi8, 3434, 343, 34, 3, 333434, 1234, ssd, ysdfsa)' => [
-                '1',
-                '5,3234,oOIUoi8,3434,343,34,3,333434,1234,ssd,ysdfsa',
-            ],
-            'pizza in (Pizza, Lasange, Strogonvo)' => [
-                'pizza',
-                'Pizza,Lasange,Strogonvo',
-            ],
-            'Eimeldingen in (Rißtissen, Überligen, Karlsruhe)' => [
-                'Eimeldingen',
-                'Rißtissen,Überligen,Karlsruhe',
-            ],
-            'überligen in (Rißtissen, Überligen, Karlsruhe)' => [
-                'überligen',
-                'Rißtissen,Überligen,Karlsruhe',
-            ],
-
-            '[12 and 14] in (11, 13, 14)' => [
-                ['12', '14'],
-                '11,13,14',
-            ],
-            '[1 and ssd] in (5, 3234, oOIUoi8, 3434, 343, 34, 3, 333434, 1234, ssd, ysdfsa)' => [
-                ['1', 'ssd'],
-                '5,3234,oOIUoi8,3434,343,34,3,333434,1234,ssd,ysdfsa',
-            ],
-            '[pizza and Lasange] in (Pizza, Lasange, Strogonvo)' => [
-                ['pizza', 'Lasange'],
-                'Pizza,Lasange,Strogonvo',
-            ],
-            '[Eimeldingen and Überligen] in (Rißtissen, Überligen, Karlsruhe)' => [
-                ['Eimeldingen', 'Ãœberligen'],
-                'Rißtissen,Überligen,Karlsruhe',
-            ],
-            '[Eimeldingen and überligen] in (Rißtissen, Überligen, Karlsruhe)' => [
-                ['Eimeldingen', 'überligen'],
-                'Rißtissen,Überligen,Karlsruhe',
-            ],
-        ];
-    }
-
-    /**
-     * used for test with invalid input
-     * will result in errors returned
-     *
-     * @return array
-     */
-    public function invalidArrayForArrayConfigurationProvider()
-    {
-        return [
-            '12 in (11, 13, 14)' => [
-                '12',
-                ['11', '13', '14'],
-            ],
-            '1 in (5, 3234, oOIUoi8, 3434, 343, 34, 3, 333434, 1234, ssd, ysdfsa)' => [
-                '1',
-                ['5', '3234', 'oOIUoi8', '3434', '343', '34', '3', '333434', '1234', 'ssd', 'ysdfsa'],
-            ],
-            'pizza in (Pizza, Lasange, Strogonvo)' => [
-                'pizza',
-                ['Pizza', 'Lasange', 'Strogonvo'],
-            ],
-            'Eimeldingen in (Rißtissen, Überligen, Karlsruhe)' => [
-                'Eimeldingen',
-                ['Rißtissen', 'Überligen', 'Karlsruhe'],
-            ],
-            'überligen in (Rißtissen, Überligen, Karlsruhe)' => [
-                'überligen',
-                ['Rißtissen', 'Überligen', 'Karlsruhe'],
-            ],
-
-            '[12 and 14] in (11, 13, 14)' => [
-                ['12', '14'],
-                ['11', '13', '14'],
-            ],
-            '[1 and ssd] in (5, 3234, oOIUoi8, 3434, 343, 34, 3, 333434, 1234, ssd, ysdfsa)' => [
-                ['1', 'ssd'],
-                ['5', '3234', 'oOIUoi8', '3434', '343', '34', '3', '333434', '1234', 'ssd', 'ysdfsa'],
-            ],
-            '[pizza and Lasange] in (Pizza, Lasange, Strogonvo)' => [
-                ['pizza', 'Lasange'],
-                ['Pizza', 'Lasange', 'Strogonvo'],
-            ],
-            '[Eimeldingen and Überligen] in (Rißtissen, Überligen, Karlsruhe)' => [
-                ['Eimeldingen', 'Ãœberligen'],
-                ['Rißtissen', 'Überligen', 'Karlsruhe'],
-            ],
-            '[Eimeldingen and überligen] in (Rißtissen, Überligen, Karlsruhe)' => [
-                ['Eimeldingen', 'überligen'],
-                ['Rißtissen', 'Überligen', 'Karlsruhe'],
-            ],
-        ];
-    }
-
-    /**
-     * used for tests with valid input
-     * ignorecase is set to true
-     * results in no errors returned
-     *
-     * @return array
-     */
-    public function validArrayForStringConfigurationIgnoreCaseProvider()
-    {
-        return [
-            '12 in (12, 13, 14)' => [
-                '12',
-                '12,13,14',
-            ],
-            '1 in (5, 3234, oOIUoi8, 3434, 343, 34, 3, 1, 333434, 1234, ssd, ysdfsa)' => [
-                '1',
-                '5,3234,oOIUoi8,3434,343,34,3,1,333434,1234,ssd,ysdfsa',
-            ],
-            'pizza in (Pizza, Lasange, Strogonvo)' => [
-                'pizza',
-                'Pizza,Lasange,Strogonvo',
-            ],
-            'Pizza in (pizza, lasange, strogonvo)' => [
-                'Pizza',
-                'pizza,lasange,strogonvo',
-            ],
-            'Rißtissen in (rißtissen, Überligen, Karlsruhe)' => [
-                'Rißtissen',
-                'rißtissen,Überligen,Karlsruhe',
-            ],
-            'überligen in (Rißtissen, Überligen, Karlsruhe)' => [
-                'überligen',
-                'Rißtissen,Überligen,Karlsruhe',
-            ],
-
-            '[12 and 14] in (12, 13, 14)' => [
-                ['12', '14'],
-                '12,13,14',
-            ],
-            '[1 and Ssd] in (5, 3234, oOIUoi8, 3434, 343, 34, 3, 1, 333434, 1234, ssd, ysdfsa)' => [
-                ['1', 'Ssd'],
-                '5,3234,oOIUoi8,3434,343,34,3,1,333434,1234,ssd,ysdfsa',
-            ],
-            '[pizza and Lasange] in (Pizza, Lasange, Strogonvo)' => [
-                ['pizza', 'Lasange'],
-                'Pizza,Lasange,Strogonvo',
-            ],
-            '[Pizza and lasange] in (pizza, lasange, strogonvo)' => [
-                ['Pizza', 'lasange'],
-                'pizza,lasange,strogonvo',
-            ],
-            '[Rißtissen and Karlsruhe] in (rißtissen, Überligen, Karlsruhe)' => [
-                ['Rißtissen', 'Karlsruhe'],
-                'rißtissen,Überligen,Karlsruhe',
-            ],
-            '[überligen and Karlsruhe] in (Rißtissen, Überligen, Karlsruhe)' => [
-                ['überligen', 'Karlsruhe'],
-                'Rißtissen,Überligen,Karlsruhe',
-            ],
-        ];
-    }
-
-    /**
-     * used for tests with valid input
-     * ignorecase is set to true
-     * results in no errors returned
-     *
-     * @return array
-     */
-    public function validArrayForArrayConfigurationIgnoreCaseProvider()
-    {
-        return [
-            '12 in [12, 13, 14]' => [
-                '12',
-                ['12', '13', '14'],
-            ],
-            '1 in [5, 3234, oOIUoi8, 3434, 343, 34, 3, 1, 333434, 1234, ssd, ysdfsa]' => [
-                '1',
-                ['5', '3234', 'oOIUoi8', '3434', '343', '34', '3', '1', '333434', '1234', 'ssd', 'ysdfsa'],
-            ],
-            'pizza in [Pizza, Lasange, Strogonvo]' => [
-                'pizza',
-                ['Pizza', 'Lasange', 'Strogonvo'],
-            ],
-            'Pizza in [pizza, lasange, strogonvo]' => [
-                'Pizza',
-                ['pizza', 'lasange', 'strogonvo'],
-            ],
-            'Rißtissen in (rißtissen, Überligen, Karlsruhe)' => [
-                'Rißtissen',
-                ['rißtissen', 'Überligen', 'Karlsruhe'],
-            ],
-            'überligen in (Rißtissen, Überligen, Karlsruhe)' => [
-                'überligen',
-                ['Rißtissen', 'Überligen', 'Karlsruhe'],
-            ],
-
-            '[12 and 14] in (12, 13, 14)' => [
-                ['12', '14'],
-                ['12', '13', '14'],
-            ],
-            '[1 and Ssd] in (5, 3234, oOIUoi8, 3434, 343, 34, 3, 1, 333434, 1234, ssd, ysdfsa)' => [
-                ['1', 'Ssd'],
-                ['5', '3234', 'oOIUoi8', '3434', '343', '34', '3', '1', '333434', '1234', 'ssd', 'ysdfsa'],
-            ],
-            '[pizza and Lasange] in (Pizza, Lasange, Strogonvo)' => [
-                ['pizza', 'Lasange'],
-                ['Pizza', 'Lasange', 'Strogonvo'],
-            ],
-            '[Pizza and lasange] in (pizza, lasange, strogonvo)' => [
-                ['Pizza', 'lasange'],
-                ['pizza', 'lasange', 'strogonvo'],
-            ],
-            '[Rißtissen and Karlsruhe] in (rißtissen, Überligen, Karlsruhe)' => [
-                ['Rißtissen', 'Karlsruhe'],
-                ['rißtissen', 'Überligen', 'Karlsruhe'],
-            ],
-            '[überligen and Karlsruhe] in (Rißtissen, Überligen, Karlsruhe)' => [
-                ['überligen', 'Karlsruhe'],
-                ['Rißtissen', 'Überligen', 'Karlsruhe'],
-            ],
-        ];
-    }
-
-    /**
-     * used for tests with invalid input
-     * ignorecase is set to true
-     * results in errors returned
-     *
-     * @return array
-     */
-    public function invalidArrayForStringConfigurationIgnoreCaseProvider()
-    {
-        return [
-            'zwölf in (12, 13, 14)' => [
-                'zwölf',
-                '12,13,14',
-            ],
-            '7 in (5, 3234, oOIUoi8, 3434, 343, 34, 3, 1, 333434, 1234, ssd, ysdfsa)' => [
-                '7',
-                '5,3234,oOIUoi8,3434,343,34,3,1,333434,1234,ssd,ysdfsa',
-            ],
-            'riss in (Rißtissen, Überligen, Karlsruhe)' => [
-                'riss',
-                'Rißtissen,Überligen,Karlsruhe',
-            ],
-            'pizzas in (Pizza, Lasange, Strogonvo)' => [
-                'pizzas',
-                'Pizza,Lasange,Strogonvo',
-            ],
-            'lusange in (Pizza, Lasange, Strogonvo)' => [
-                'lusange',
-                'Pizza,Lasange,Strogonvo',
-            ],
-
-            '[zwölf and 14] in (12, 13, 14)' => [
-                ['zwölf', '14'],
-                '12,13,14',
-            ],
-            '[7 and Ssd] in (5, 3234, oOIUoi8, 3434, 343, 34, 3, 1, 333434, 1234, ssd, ysdfsa)' => [
-                ['7', 'Ssd'],
-                '5,3234,oOIUoi8,3434,343,34,3,1,333434,1234,ssd,ysdfsa',
-            ],
-            '[riss and Karlsruhe] in (Rißtissen, Überligen, Karlsruhe)' => [
-                ['riss', 'Karlsruhe'],
-                'Rißtissen,Überligen,Karlsruhe',
-            ],
-            '[pizzas and Lasange] in (Pizza, Lasange, Strogonvo)' => [
-                ['pizzas', 'Lasange'],
-                'Pizza,Lasange,Strogonvo',
-            ],
-            '[lusange and Strogonvo] in (Pizza, Lasange, Strogonvo)' => [
-                ['lusange', 'Strogonvo'],
-                'Pizza,Lasange,Strogonvo',
-            ],
-        ];
-    }
-
-    /**
-     * used for tests with invalid input
-     * ignorecase is set to true
-     * results in errors returned
-     *
-     * @return array
-     */
-    public function invalidArrayForArrayConfigurationIgnoreCaseProvider()
-    {
-        return [
-            'zwölf in (12, 13, 14)' => [
-                'zwölf',
-                ['12', '13', '14'],
-            ],
-            '7 in (5, 3234, oOIUoi8, 3434, 343, 34, 3, 1, 333434, 1234, ssd, ysdfsa)' => [
-                '7',
-                ['5', '3234', 'oOIUoi8', '3434', '343', '34', '3', '1', '333434', '1234', 'ssd', 'ysdfsa'],
-            ],
-            'riss in (Rißtissen, Überligen, Karlsruhe)' => [
-                'riss',
-                ['Rißtissen', 'Überligen', 'Karlsruhe'],
-            ],
-            'pizzas in (Pizza, Lasange, Strogonvo)' => [
-                'pizzas',
-                ['Pizza', 'Lasange', 'Strogonvo'],
-            ],
-            'lusange in (Pizza, Lasange, Strogonvo)' => [
-                'lusange',
-                ['Pizza', 'Lasange', 'Strogonvo'],
-            ],
-
-            '[zwölf and 14] in (12, 13, 14)' => [
-                ['zwölf', '14'],
-                ['12', '13', '14'],
-            ],
-            '[7 and Ssd] in (5, 3234, oOIUoi8, 3434, 343, 34, 3, 1, 333434, 1234, ssd, ysdfsa)' => [
-                ['7', 'Ssd'],
-                ['5', '3234', 'oOIUoi8', '3434', '343', '34', '3', '1', '333434', '1234', 'ssd', 'ysdfsa'],
-            ],
-            '[riss and Karlsruhe] in (Rißtissen, Überligen, Karlsruhe)' => [
-                ['riss', 'Karlsruhe'],
-                ['Rißtissen', 'Überligen', 'Karlsruhe'],
-            ],
-            '[pizzas and Lasange] in (Pizza, Lasange, Strogonvo)' => [
-                ['pizzas', 'Lasange'],
-                ['Pizza', 'Lasange', 'Strogonvo'],
-            ],
-            '[lusange and Strogonvo] in (Pizza, Lasange, Strogonvo)' => [
-                ['lusange', 'Strogonvo'],
-                ['Pizza', 'Lasange', 'Strogonvo'],
-            ],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validArrayForStringConfigurationProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForValidInputOnStringConfigurationReturnsNoErrors($value, $allowedOptionsString)
-    {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-
-        $options['array'] = $allowedOptionsString;
-        $subject = $this->createSubject($options);
-
-        $this->assertFalse($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider validArrayForArrayConfigurationProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForValidInputOnArrayConfigurationReturnsNoErrors($value, $allowedOptionsString)
-    {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array.'] = $allowedOptionsString;
-        $subject = $this->createSubject($options);
-
-        $this->assertFalse($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidArrayForStringConfigurationProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForInvalidInputOnStringConfigurationReturnsErrors($value, $allowedOptionsString)
-    {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array'] = $allowedOptionsString;
-        $subject = $this->createSubject($options);
-
-        $this->assertTrue($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidArrayForArrayConfigurationProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForInvalidInputOnArrayConfigurationReturnsErrors($value, $allowedOptionsString)
-    {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array.'] = $allowedOptionsString;
-        $subject = $this->createSubject($options);
-
-        $this->assertTrue($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider validArrayForStringConfigurationProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForValidInputOnStringConfigurationWithStrictComparisonReturnsNoErrors(
-        $value,
-        $allowedOptionsString
-    ) {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array'] = $allowedOptionsString;
-        $options['strict'] = true;
-        $subject = $this->createSubject($options);
-
-        $this->assertFalse($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider validArrayForArrayConfigurationProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForValidInputOnArrayConfigurationWithStrictComparisonReturnsNoErrors(
-        $value,
-        $allowedOptionsString
-    ) {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array.'] = $allowedOptionsString;
-        $options['strict'] = true;
-        $subject = $this->createSubject($options);
-
-        $this->assertFalse($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidArrayForStringConfigurationProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForInvalidInputOnStringConfigurationWithStrictComparisonReturnsErrors(
-        $value,
-        $allowedOptionsString
-    ) {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array'] = $allowedOptionsString;
-        $options['strict'] = true;
-        $subject = $this->createSubject($options);
-
-        $this->assertTrue($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidArrayForArrayConfigurationProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForInvalidInputOnArrayConfigurationWithStrictComparisonReturnsErrors(
-        $value,
-        $allowedOptionsString
-    ) {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array.'] = $allowedOptionsString;
-        $options['strict'] = true;
-        $subject = $this->createSubject($options);
-
-        $this->assertTrue($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider validArrayForStringConfigurationIgnoreCaseProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForValidInputOnStringConfigurationWithIgnoreCaseReturnsNoErrors(
-        $value,
-        $allowedOptionsString
-    ) {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array'] = $allowedOptionsString;
-        $options['ignorecase'] = true;
-        $subject = $this->createSubject($options);
-
-        $this->assertFalse($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider validArrayForArrayConfigurationIgnoreCaseProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForValidInputOnArrayConfigurationWithIgnoreCaseReturnsNoErrors(
-        $value,
-        $allowedOptionsString
-    ) {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array.'] = $allowedOptionsString;
-        $options['ignorecase'] = true;
-        $subject = $this->createSubject($options);
-
-        $this->assertFalse($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidArrayForStringConfigurationIgnoreCaseProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForInvalidInputOnStringConfigurationWithIgnoreCaseReturnsErrors(
-        $value,
-        $allowedOptionsString
-    ) {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array'] = $allowedOptionsString;
-        $options['ignorecase'] = true;
-        $subject = $this->createSubject($options);
-
-        $this->assertTrue($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidArrayForArrayConfigurationIgnoreCaseProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForInvalidInputOnArrayConfigurationWithIgnoreCaseReturnsErrors(
-        $value,
-        $allowedOptionsString
-    ) {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array.'] = $allowedOptionsString;
-        $options['ignorecase'] = true;
-        $subject = $this->createSubject($options);
-
-        $this->assertTrue($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider validArrayForStringConfigurationIgnoreCaseProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForValidInputOnStringConfigurationWithIgnoreCaseAndStrictReturnsNoErrors(
-        $value,
-        $allowedOptionsString
-    ) {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array'] = $allowedOptionsString;
-        $options['ignorecase'] = true;
-        $options['strict'] = true;
-        $subject = $this->createSubject($options);
-
-        $this->assertFalse($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider validArrayForArrayConfigurationIgnoreCaseProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForValidInputOnArrayConfigurationWithIgnoreCaseAndStrictReturnsNoErrors(
-        $value,
-        $allowedOptionsString
-    ) {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array.'] = $allowedOptionsString;
-        $options['ignorecase'] = true;
-        $options['strict'] = true;
-        $subject = $this->createSubject($options);
-
-        $this->assertFalse($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidArrayForStringConfigurationIgnoreCaseProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForInvalidInputOnStringConfigurationWithIgnoreCaseAndStrictReturnsErrors(
-        $value,
-        $allowedOptionsString
-    ) {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array'] = $allowedOptionsString;
-        $options['ignorecase'] = true;
-        $options['strict'] = true;
-        $subject = $this->createSubject($options);
-
-        $this->assertTrue($subject->validate($value)->hasErrors());
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidArrayForArrayConfigurationIgnoreCaseProvider
-     *
-     * @param string $value
-     * @param string $allowedOptionsString
-     */
-    public function validateForInvalidInputOnArrayConfigurationWithIgnoreCaseAndStrictReturnsErrors(
-        $value,
-        $allowedOptionsString
-    ) {
-        $options = [
-            'element' => uniqid('test'),
-            'errorMessage' => uniqid('error'),
-        ];
-        $options['array.'] = $allowedOptionsString;
-        $options['ignorecase'] = true;
-        $options['strict'] = true;
-        $subject = $this->createSubject($options);
-
-        $this->assertTrue($subject->validate($value)->hasErrors());
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/IntegerValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/IntegerValidatorTest.php
deleted file mode 100644
index db8e2f167429930279580523b94ca54af9363e69..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/IntegerValidatorTest.php
+++ /dev/null
@@ -1,90 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class IntegerValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\IntegerValidator::class;
-
-    public function validateForValidInputHasEmptyErrorResultDataProvider()
-    {
-        return [
-            '12 for de locale' => [
-                12,
-                'de_DE.utf8'
-            ],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validateForValidInputHasEmptyErrorResultDataProvider
-     */
-    public function validateForValidInputHasEmptyErrorResult($value, $locale)
-    {
-        try {
-            $this->setLocale(LC_NUMERIC, $locale);
-        } catch (\PHPUnit_Framework_Exception $e) {
-            $this->markTestSkipped('Locale ' . $locale . ' is not available.');
-        }
-
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($value)->getErrors()
-        );
-    }
-
-    public function validateForInvalidInputHasNotEmptyErrorResultDataProvider()
-    {
-        return [
-            '12.1 for en_US locale' => [
-                12.1,
-                'en_US.utf8'
-            ],
-            '12,1 for de_DE locale' => [
-                '12,1',
-                'de_DE.utf8'
-            ],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validateForInvalidInputHasNotEmptyErrorResultDataProvider
-     */
-    public function validateForInvalidInputHasNotEmptyErrorResult($value, $locale)
-    {
-        try {
-            $this->setLocale(LC_NUMERIC, $locale);
-        } catch (\PHPUnit_Framework_Exception $e) {
-            $this->markTestSkipped('Locale ' . $locale . ' is not available.');
-        }
-
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($value)->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/IpValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/IpValidatorTest.php
deleted file mode 100644
index 1c1f0bf398327d65eddc5ed9359e0fc807d8d322..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/IpValidatorTest.php
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class IpValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\IpValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validIpv4Provider()
-    {
-        return [
-            '127.0.0.1'   => ['127.0.0.1'],
-            '10.0.0.4'    => ['10.0.0.4'],
-            '192.168.0.4' => ['192.168.0.4'],
-            '0.0.0.0'     => ['0.0.0.0']
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidIpv4Provider()
-    {
-        return [
-            '127.0.0.256' => ['127.0.0.256'],
-            '256.0.0.2'   => ['256.0.0.2']
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validIpv4Provider
-     */
-    public function validateForValidInputHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidIpv4Provider
-     */
-    public function validateForInvalidInputHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/LengthValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/LengthValidatorTest.php
deleted file mode 100644
index d78086ab6026a8b892fe4453f085f40906fe6d12..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/LengthValidatorTest.php
+++ /dev/null
@@ -1,127 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use Prophecy\Argument;
-use TYPO3\CMS\Core\Charset\CharsetConverter;
-use TYPO3\CMS\Form\Domain\Validator\LengthValidator;
-
-/**
- * Test case
- */
-class LengthValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\LengthValidator::class;
-
-    /**
-     * @var \Prophecy\Prophecy\ObjectProphecy
-     */
-    protected $charsetConverterProphecy;
-
-    /**
-     * Set up
-     */
-    protected function setUp()
-    {
-        parent::setUp();
-        $this->charsetConverterProphecy = $this->prophesize(CharsetConverter::class);
-        $this->charsetConverterProphecy
-            ->strlen(Argument::cetera())
-            ->will(function ($arguments) {
-                return mb_strlen($arguments[1], $arguments[0]);
-            });
-    }
-
-    protected function tearDown()
-    {
-        parent::tearDown();
-        unset($this->charsetConverterProphecy);
-    }
-
-    /**
-     * @return array
-     */
-    public function validLengthProvider()
-    {
-        return [
-            '4 ≤ length(myString) ≤ 8' => [
-                [4, 8, 'mäString']
-            ],
-            '8 ≤ length(myString) ≤ 8' => [
-                [8, 8, 'möString']
-            ],
-            '4 ≤ length(myString)' => [
-                [4, null, 'myString']
-            ],
-            '4 ≤ length(asdf) ≤ 4' => [
-                [4, 4, 'asdf']
-            ],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validLengthProvider
-     */
-    public function validateForValidInputHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['minimum'] = $input[0];
-        $options['maximum'] = $input[1];
-        /** @var LengthValidator $subject */
-        $subject = $this->createSubject($options);
-        $subject->injectCharsetConverter($this->charsetConverterProphecy->reveal());
-
-        $this->assertEmpty(
-            $subject->validate($input[2])->getErrors()
-        );
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidLengthProvider()
-    {
-        return [
-            '4 ≤ length(my) ≤ 12' => [
-                [4, 12, 'my']
-            ],
-            '4 ≤ length(my long string) ≤ 12' => [
-                [4, 12, 'my long string']
-            ],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidLengthProvider
-     */
-    public function validateForInvalidInputHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['minimum'] = $input[0];
-        $options['maximum'] = $input[1];
-        /** @var LengthValidator $subject */
-        $subject = $this->createSubject($options);
-        $subject->injectCharsetConverter($this->charsetConverterProphecy->reveal());
-
-        $this->assertNotEmpty(
-            $subject->validate($input[2])->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/LessThanValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/LessThanValidatorTest.php
deleted file mode 100644
index e665e6058ced7c3c6da670c7798788965b805c8a..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/LessThanValidatorTest.php
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class LessThanValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\LessThanValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validValueProvider()
-    {
-        return [
-            '4 < 8' => [[8, 4]],
-            '7.9 < 8' => [[8, 7.9]],
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidValueProvider()
-    {
-        return [
-            '8 < 4' => [[4, 8]],
-            '8 < 8' => [[8, 8]],
-            '8.1 < 8' => [[8, 8.1]],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validValueProvider
-     */
-    public function validateForValidInputHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['maximum'] = $input[0];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidValueProvider
-     */
-    public function validateForInvalidInputHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['maximum'] = $input[0];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/RegExpValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/RegExpValidatorTest.php
deleted file mode 100644
index 4e3708bfec4405703c015138fcc927f8487ed11e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/RegExpValidatorTest.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class RegExpValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\RegExpValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validDataProvider()
-    {
-        return [
-            '/^a/ matches a' => [['/^a/', 'a']],
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidDataProvider()
-    {
-        return [
-            '/[^\d]/ matches 8' => [['/[^\d]/', 8]],
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validDataProvider
-     */
-    public function validateForValidInputHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['expression'] = $input[0];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidDataProvider
-     */
-    public function validateForInvalidInputHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $options['expression'] = $input[0];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input[1])->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/RequiredValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/RequiredValidatorTest.php
deleted file mode 100644
index 13ab0612468947e765be2fd5f60c5e7013a1774e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/RequiredValidatorTest.php
+++ /dev/null
@@ -1,87 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class RequiredValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\RequiredValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validDataProvider()
-    {
-        return [
-            'string "a"'   => ['a'],
-            'string "a b"' => ['a b'],
-            'string "0"'   => ['0'],
-            'value 0'      => [0],
-            'array with string "a"'   => [['a']],
-            'array with string "a b"' => [['a b']],
-            'array with string "0"'   => [['0']],
-            'array with value 0'      => [[0]],
-            'array with strings "a" and "b"' => [['a', 'b']],
-            'array with empty string and "a"' => [['', 'a']],
-            'array with empty string and "0"' => [['', '0']],
-            'array with empty string and 0' => [['', 0]],
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidDataProvider()
-    {
-        return [
-            'empty string'            => [''],
-            'array with empty string' => [['']],
-            'array with empty strings' => [['', '']]
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validDataProvider
-     */
-    public function validateForValidDataHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidDataProvider
-     */
-    public function validateForInvalidDataHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/Validator/UriValidatorTest.php b/typo3/sysext/form/Tests/Unit/Validator/UriValidatorTest.php
deleted file mode 100644
index 6367b8000427ed855b408db02f81fa60f585eb5e..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/Tests/Unit/Validator/UriValidatorTest.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-namespace TYPO3\CMS\Form\Tests\Unit\Validator;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class UriValidatorTest extends AbstractValidatorTest
-{
-    /**
-     * @var string
-     */
-    protected $subjectClassName = \TYPO3\CMS\Form\Domain\Validator\UriValidator::class;
-
-    /**
-     * @return array
-     */
-    public function validDataProvider()
-    {
-        return [
-            'http://example.net'              => ['http://example.net'],
-            'https://example.net'             => ['https://example.net'],
-            'http://a:b@example.net'          => ['http://a:b@example.net'],
-        ];
-    }
-
-    /**
-     * @return array
-     */
-    public function invalidDataProvider()
-    {
-        return [
-            'index.php' => ['index.php']
-        ];
-    }
-
-    /**
-     * @test
-     * @dataProvider validDataProvider
-     */
-    public function validateForValidInputHasEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-
-    /**
-     * @test
-     * @dataProvider invalidDataProvider
-     */
-    public function validateForInvalidInputHasNotEmptyErrorResult($input)
-    {
-        $options = ['element' => uniqid('test'), 'errorMessage' => uniqid('error')];
-        $subject = $this->createSubject($options);
-
-        $this->assertNotEmpty(
-            $subject->validate($input)->getErrors()
-        );
-    }
-}
diff --git a/typo3/sysext/form/Tests/Unit/ViewHelpers/Form/DatePickerViewHelperTest.php b/typo3/sysext/form/Tests/Unit/ViewHelpers/Form/DatePickerViewHelperTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..edb28f043f6cdfaa4c2ddac04bed30dfd5ed52fb
--- /dev/null
+++ b/typo3/sysext/form/Tests/Unit/ViewHelpers/Form/DatePickerViewHelperTest.php
@@ -0,0 +1,143 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Form\Tests\Unit\ViewHelpers\Form;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Form\ViewHelpers\Form\DatePickerViewHelper;
+
+/**
+ * Test case
+ */
+class DatePickerViewHelperTest extends UnitTestCase
+{
+
+    /**
+     * @var \TYPO3\CMS\Form\ViewHelpers\Form\DatePickerViewHelper
+     */
+    protected $subject = null;
+
+    /**
+     * Set up
+     *
+     * @return void
+     */
+    protected function setUp()
+    {
+        $this->subject = $this->getAccessibleMock(DatePickerViewHelper::class, [
+            'dummy'
+        ], [], '', false);
+    }
+
+    /**
+     * @test
+     */
+    public function convertDateFormatToDatePickerFormatReturnsTransformedFormat01()
+    {
+        $input = 'd';
+        $expected = 'dd';
+        $this->assertSame($expected, $this->subject->_call('convertDateFormatToDatePickerFormat', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function convertDateFormatToDatePickerFormatReturnsTransformedFormat02()
+    {
+        $input = 'D';
+        $expected = 'D';
+        $this->assertSame($expected, $this->subject->_call('convertDateFormatToDatePickerFormat', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function convertDateFormatToDatePickerFormatReturnsTransformedFormat03()
+    {
+        $input = 'j';
+        $expected = 'o';
+        $this->assertSame($expected, $this->subject->_call('convertDateFormatToDatePickerFormat', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function convertDateFormatToDatePickerFormatReturnsTransformedFormat04()
+    {
+        $input = 'l';
+        $expected = 'DD';
+        $this->assertSame($expected, $this->subject->_call('convertDateFormatToDatePickerFormat', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function convertDateFormatToDatePickerFormatReturnsTransformedFormat05()
+    {
+        $input = 'F';
+        $expected = 'MM';
+        $this->assertSame($expected, $this->subject->_call('convertDateFormatToDatePickerFormat', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function convertDateFormatToDatePickerFormatReturnsTransformedFormat06()
+    {
+        $input = 'm';
+        $expected = 'mm';
+        $this->assertSame($expected, $this->subject->_call('convertDateFormatToDatePickerFormat', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function convertDateFormatToDatePickerFormatReturnsTransformedFormat07()
+    {
+        $input = 'M';
+        $expected = 'M';
+        $this->assertSame($expected, $this->subject->_call('convertDateFormatToDatePickerFormat', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function convertDateFormatToDatePickerFormatReturnsTransformedFormat08()
+    {
+        $input = 'n';
+        $expected = 'm';
+        $this->assertSame($expected, $this->subject->_call('convertDateFormatToDatePickerFormat', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function convertDateFormatToDatePickerFormatReturnsTransformedFormat09()
+    {
+        $input = 'Y';
+        $expected = 'yy';
+        $this->assertSame($expected, $this->subject->_call('convertDateFormatToDatePickerFormat', $input));
+    }
+
+    /**
+     * @test
+     */
+    public function convertDateFormatToDatePickerFormatReturnsTransformedFormat10()
+    {
+        $input = 'y';
+        $expected = 'y';
+        $this->assertSame($expected, $this->subject->_call('convertDateFormatToDatePickerFormat', $input));
+    }
+}
diff --git a/typo3/sysext/form/composer.json b/typo3/sysext/form/composer.json
index 33e88b4a256d6cf2ac484c83f540d9feffacc262..532111b80b2766e25b4e792142fcde7379554d38 100644
--- a/typo3/sysext/form/composer.json
+++ b/typo3/sysext/form/composer.json
@@ -1,31 +1,31 @@
 {
-	"name": "typo3/cms-form",
-	"type": "typo3-cms-framework",
-	"description": "TYPO3 Core",
-	"homepage": "https://typo3.org",
-	"license": ["GPL-2.0+"],
+    "name": "typo3/cms-form",
+    "type": "typo3-cms-framework",
+    "description": "Extensible and flexible API and editor for building web forms",
+    "homepage": "https://typo3.org",
+    "license": ["GPL-2.0+"],
 
-	"require": {
-		"typo3/cms-core": "*"
-	},
-	"replace": {
-		"form": "*"
-	},
-	"extra": {
-		"typo3/cms": {
-			"Package": {
-				"partOfFactoryDefault": true
-			}
-		}
-	},
-	"autoload": {
-		"psr-4": {
-			"TYPO3\\CMS\\Form\\": "Classes/"
-		}
-	},
-	"autoload-dev": {
-		"psr-4": {
-			"TYPO3\\CMS\\Form\\Tests\\": "Tests/"
-		}
-	}
+    "require": {
+        "typo3/cms-core": "*"
+    },
+    "replace": {
+        "form": "*"
+    },
+    "extra": {
+        "typo3/cms": {
+            "Package": {
+                "partOfFactoryDefault": true
+            }
+        }
+    },
+    "autoload": {
+        "psr-4": {
+            "TYPO3\\CMS\\Form\\": "Classes/"
+        }
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "TYPO3\\CMS\\Form\\Tests\\": "Tests/"
+        }
+    }
 }
diff --git a/typo3/sysext/form/ext_emconf.php b/typo3/sysext/form/ext_emconf.php
index 22ce0118f67104432bcde81b596d1b189d9b3bb8..08321e979ce597f3cea7385f8c71c9750b3f784c 100644
--- a/typo3/sysext/form/ext_emconf.php
+++ b/typo3/sysext/form/ext_emconf.php
@@ -1,14 +1,14 @@
 <?php
 $EM_CONF[$_EXTKEY] = [
     'title' => 'Form',
-    'description' => 'Form Library, Plugin and Wizard',
-    'category' => 'plugin',
+    'description' => 'Form Library, Plugin and Editor',
+    'category' => 'misc',
     'state' => 'beta',
     'uploadfolder' => 0,
     'createDirs' => '',
     'clearCacheOnLoad' => 1,
-    'author' => 'Patrick Broens, Ralf Zimmermann',
-    'author_email' => 'patrick@patrickbroens.nl, ralf.zimmermann@tritum.de',
+    'author' => 'Form Team',
+    'author_email' => '',
     'author_company' => '',
     'version' => '8.5.0',
     'constraints' => [
diff --git a/typo3/sysext/form/ext_localconf.php b/typo3/sysext/form/ext_localconf.php
index 511c41d247fd82e4ed30494768b038c070cdfa9d..0be93ed71c1e27129a7c0ec0a6fd4f782de6d1ef 100644
--- a/typo3/sysext/form/ext_localconf.php
+++ b/typo3/sysext/form/ext_localconf.php
@@ -1,47 +1,66 @@
 <?php
 defined('TYPO3_MODE') or die();
 
-if (TYPO3_MODE === 'BE') {
-    // Apply PageTSconfig
+call_user_func(function () {
+    // Register FE plugin
+    \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
+        'TYPO3.CMS.Form',
+        'Formframework',
+        ['FormFrontend' => 'render, perform'],
+        ['FormFrontend' => 'perform'],
+        \TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT
+    );
+
+    // Add new content element wizard entry
     \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig(
         '<INCLUDE_TYPOSCRIPT: source="FILE:EXT:form/Configuration/PageTS/modWizards.ts">'
     );
 
-    // Add default User TS Config FORM configuration
-    \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addUserTSConfig(
-        '<INCLUDE_TYPOSCRIPT: source="FILE:EXT:form/Configuration/UserTSconfig/userTSConfig.txt">'
+    // FE file upload processing
+    \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerTypeConverter(
+        \TYPO3\CMS\Form\Mvc\Property\TypeConverter\UploadedFileReferenceConverter::class
     );
 
-    // Backend view
-    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawItem']['mailform'] =
-        \TYPO3\CMS\Form\Hooks\PageLayoutView\MailformPreviewRenderer::class;
-
-    $GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1440772316] = [
-        'nodeName' => 'formwizard',
-        'priority' => 40,
-        'class'    => \TYPO3\CMS\Form\View\Wizard\Element\FormWizardElement::class,
-    ];
-}
-
-// Extbase handling
-\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerTypeConverter(
-    \TYPO3\CMS\Form\Domain\Property\TypeConverter\ArrayToValidationElementConverter::class
-);
-
-\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
-    'TYPO3.CMS.Form',
-    'Form',
-    ['Frontend' => 'show, confirmation, dispatchConfirmationButtonClick, process, afterProcess'],
-    ['Frontend' => 'show, confirmation, dispatchConfirmationButtonClick, process, afterProcess']
-);
+    // Hook to enrich tt_content form flex element with finisher settings and form list drop down
+    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][\TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools::class]['flexParsing'][
+        \TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook::class
+    ] = \TYPO3\CMS\Form\Hooks\DataStructureIdentifierHook::class;
 
-\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class)
-    ->connect(
-        \TYPO3\CMS\Form\Domain\Builder\FormBuilder::class,
-        'txFormHandleIncomingValues',
-        \TYPO3\CMS\Form\Hooks\HandleIncomingFormValues::class,
-        'handleIncomingFormValues'
-    );
+    // Hook to count used forms elements in tt_content
+    $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser']['formPersistenceIdentifier'] =
+        \TYPO3\CMS\Form\Hooks\SoftReferenceParserHook::class;
 
-// Register the extbase plugin as shorthand for typoscript 10 = FORM
-$GLOBALS['TYPO3_CONF_VARS']['FE']['ContentObjects']['FORM'] = \TYPO3\CMS\Form\ContentObject\FormContentObject::class;
+    // Add a bunch of icons to icon registry
+    $iconIdentifiers = [
+        'advanced-password',
+        'checkbox',
+        'content-element',
+        'date-picker',
+        'duplicate',
+        'fieldset',
+        'file-upload',
+        'finisher',
+        'image-upload',
+        'insert-after',
+        'insert-in',
+        'multi-checkbox',
+        'multi-select',
+        'page',
+        'password',
+        'radio-button',
+        'single-select',
+        'static-text',
+        'summary-page',
+        'text',
+        'textarea',
+        'validator'
+    ];
+    $iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class);
+    foreach ($iconIdentifiers as $iconIdentifier) {
+        $iconRegistry->registerIcon(
+            't3-form-icon-' . $iconIdentifier,
+            \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class,
+            ['source' => 'EXT:form/Resources/Public/Images/' . $iconIdentifier . '.svg']
+        );
+    }
+});
diff --git a/typo3/sysext/form/ext_tables.php b/typo3/sysext/form/ext_tables.php
new file mode 100644
index 0000000000000000000000000000000000000000..c036107a9a71588387fa913a939e4a8b14c0f318
--- /dev/null
+++ b/typo3/sysext/form/ext_tables.php
@@ -0,0 +1,21 @@
+<?php
+defined('TYPO3_MODE') or die();
+
+// Register the backend module Web->Forms
+\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerModule(
+    'TYPO3.CMS.Form',
+    'web',
+    'formbuilder',
+    '',
+    [
+        'FormManager' => 'index, show, create, duplicate, references, delete',
+        'FormEditor' => 'index, saveForm, renderFormPage, renderRenderableOptions',
+    ],
+    [
+        'access' => 'user,group',
+        'icon' => 'EXT:form/Resources/Public/Icons/Extension.png',
+        'labels' => 'LLL:EXT:form/Resources/Private/Language/locallang_module.xlf',
+        'navigationComponentId' => '',
+        'inheritNavigationComponentFromMainModule' => false
+    ]
+);
diff --git a/typo3/sysext/form/ext_tables.sql b/typo3/sysext/form/ext_tables.sql
deleted file mode 100644
index 3fe240733fd62bd95eeb60d24b72eea83dec2ff4..0000000000000000000000000000000000000000
--- a/typo3/sysext/form/ext_tables.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Table structure for table 'tt_content'
-#
-CREATE TABLE tt_content (
-	tx_form_predefinedform varchar(255) DEFAULT '' NOT NULL
-);
diff --git a/typo3/sysext/form/ext_typoscript_setup.txt b/typo3/sysext/form/ext_typoscript_setup.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a47e55edca49d728e06e86519dcf96d860d03d7b
--- /dev/null
+++ b/typo3/sysext/form/ext_typoscript_setup.txt
@@ -0,0 +1,2 @@
+<INCLUDE_TYPOSCRIPT: source="FILE:EXT:form/Configuration/TypoScript/setup.txt">
+<INCLUDE_TYPOSCRIPT: source="FILE:EXT:form/Configuration/TypoScript/backend.txt">
\ No newline at end of file