Commit 553681a2 authored by Ralf Zimmermann's avatar Ralf Zimmermann Committed by Christian Kuhn
Browse files

[FEATURE] EXT:form - integrate new form framework

The main purpose of this patch is to integrate a flexible framework for
building forms. 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 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 - which
is part of a future patch - will explain the ideas, concept and
architecture as well as the functionality in detail.

This patch marks the beginning of a series of patches. Further work is
needed to implement a better UI and more tests. The currently integrated
element tree cannot be finished for now. We plan to use the new TYPO3
SVG tree but have to wait for the drag and drop implementation.
Furthermore, the old form wizard will be moved to a separate extension
for backward compatibility.

Resolves: #77910
Releases: master
Change-Id: Idde8453bc573da835959fa3e51e30f57792d98b0
Reviewed-on: https://review.typo3.org/50311


Tested-by: default avatarTYPO3com <no-reply@typo3.com>
Reviewed-by: Björn Jacob's avatarBjoern Jacob <bjoern.jacob@tritum.de>
Tested-by: Björn Jacob's avatarBjoern Jacob <bjoern.jacob@tritum.de>
Reviewed-by: default avatarRalf Zimmermann <ralf.zimmermann@tritum.de>
Tested-by: default avatarRalf Zimmermann <ralf.zimmermann@tritum.de>
Reviewed-by: Anja Leichsenring's avatarAnja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring's avatarAnja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Frank Nägler's avatarFrank Naegler <frank.naegler@typo3.org>
Tested-by: Frank Nägler's avatarFrank Naegler <frank.naegler@typo3.org>
Reviewed-by: Alexander Opitz's avatarAlexander Opitz <opitz.alexander@googlemail.com>
Tested-by: Alexander Opitz's avatarAlexander Opitz <opitz.alexander@googlemail.com>
Reviewed-by: Andreas Häfner's avatarAndreas Häfner <andreas.haefner@tritum.de>
Tested-by: Andreas Häfner's avatarAndreas Häfner <andreas.haefner@tritum.de>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
parent 77377a76
@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;