Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
typo3
qfq
Commits
2e0e3a4d
Commit
2e0e3a4d
authored
Nov 22, 2019
by
Carsten Rose
Browse files
Merge branch 'F9617-SaveRequired' into 'master'
F9617 save required See merge request
!201
parents
8c5a4d37
5c6bbe72
Pipeline
#2734
passed with stages
in 2 minutes and 59 seconds
Changes
9
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Documentation/Manual.rst
View file @
2e0e3a4d
...
...
@@ -2436,11 +2436,11 @@ After the user presses *Save*, *Close*, *Delete* or *New*, different actions are
to a previous page. The decision depends on:
* *Close* goes back (feels like close) to the previous page. Note: if there is no history, QFQ won't close the tab,
instead a message is shown.
instead a message is shown.
* *Save* stays on the current page.
* `close` - goes back (feels like close) to the previous page. Note: if there is no history, QFQ won't close the tab,
instead a message is shown.
instead a message is shown.
* `no` - no change, the browser remains on the current side. Close does not close the page. It just triggers a save if
there are modified data.
* `url` - the browser redirects to the URL or T3 page named in `Forward URL / Page`. Independent if the user presses `save` or `close`.
...
...
@@ -2481,7 +2481,7 @@ The CLIENT `submit_reason` shows the user action:
Example forwardPage
^^^^^^^^^^^^^^^^^^^
* `{{SELECT IF('{{formModeGlobal:S}}'='
r
equired
Off
', 'no', 'auto') }}`
* `{{SELECT IF('{{formModeGlobal:S}}'='
skipR
equired
Check
', 'no', 'auto') }}`
* `{{SELECT IF('{{submit_reason:CE:alnumx}}'='save', 'no', 'url'), '|http://example.com' }}`
Type: combined dynamic mode & URL/page
...
...
@@ -2690,27 +2690,31 @@ The Form global mode `mode` is given by default with `{{formModeGlobal:SE:alnumx
Optional it might be defined via *Form.parameter* ::
mode=readonly|
r
equired
Off
mode=readonly|
skipR
equired
Check
* `readonly`: all `FormElement` of the whole form are temporarily in `readonly` mode. This is a fast way to use an
existing *Form* just to display the form data, without a possibility for the user to change any data of the form.
* `requiredOff`: all `FormElement` of the whole, with `mode=required`, will temporarily switch to `mode=show`. In this
mode, the user might save the form without providing all necessary data. Later on, when application logic requires a
final submit, this mode is not used any longer (call the form as regular without the 'formModeGlobal' parameter) and
the form can only be saved with all data given.
Than, e.g. an action-FormElement 'afterSave' can be used to detect the final submit situation and do some extra stuff,
necessary for the final submit.
* `skipRequiredCheck`:
The following shows the same *Form* in the `regular`, `readonly` and `requiredOff` mode::
* All `FormElement` with `mode=required`, will switch to `mode=show`.
* The user might save the form without providing all necessary data.
* Calling the form without this mode (regular), the form can only be saved with all data given. Than, e.g. an
action-FormElement 'afterSave' can be used to detect the final submit situation and do some extra stuff,
necessary for a final submit.
* `requiredOff` is a deprecated synonym of `skipRequiredCheck`.
The following shows the same *Form* in the `regular`, `readonly` and `skipRequiredCheck` mode::
10.sql = SELECT CONCAT('p:{{pageAlias:T}}&form=person&r=', p.id, '|Regular') as _pagee,
CONCAT('p:{{pageAlias:T}}&form=person&formModeGlobal=readonly&r=', p.id, '|Readonly') as _pagee,
CONCAT('p:{{pageAlias:T}}&form=person&formModeGlobal=
r
equired
Off
&r=', p.id, '|Required off') as _pagee
CONCAT('p:{{pageAlias:T}}&form=person&formModeGlobal=
skipR
equired
Check
&r=', p.id, '|Required off') as _pagee
FROM Person AS p
..
FormElements
------------
...
...
extension/Classes/Core/AbstractBuildForm.php
View file @
2e0e3a4d
...
...
@@ -987,8 +987,7 @@ abstract class AbstractBuildForm {
for
(
$i
=
0
;
$i
<
count
(
$this
->
feSpecNative
);
++
$i
)
{
// Only check native elements which will be shown
if
(
$this
->
feSpecNative
[
$i
][
FE_CLASS
]
==
FE_CLASS_NATIVE
&&
(
$this
->
feSpecNative
[
$i
][
FE_MODE
]
==
FE_MODE_SHOW
||
$this
->
feSpecNative
[
$i
][
FE_MODE
]
==
FE_MODE_REQUIRED
||
$this
->
feSpecNative
[
$i
][
FE_MODE
]
==
FE_MODE_SHOW_REQUIRED
)
(
$this
->
feSpecNative
[
$i
][
FE_MODE
]
==
FE_MODE_SHOW
||
$this
->
feSpecNative
[
$i
][
FE_MODE
]
==
FE_MODE_REQUIRED
)
)
{
// Check if there is an explicit definition.
if
(
isset
(
$this
->
feSpecNative
[
$i
][
FE_AUTOFOCUS
]))
{
...
...
@@ -1144,7 +1143,7 @@ abstract class AbstractBuildForm {
// }
}
if
(
$formElement
[
FE_MODE
]
==
FE_MODE_REQUIRED
||
$formElement
[
FE_MODE
]
==
FE_MODE_SHOW_REQUIRED
)
{
if
(
$formElement
[
FE_MODE
]
==
FE_MODE_REQUIRED
)
{
$addClassRequired
=
HelperFormElement
::
getRequiredPositionClass
(
$formElement
[
F_FE_REQUIRED_POSITION
]);
}
...
...
@@ -1250,7 +1249,6 @@ abstract class AbstractBuildForm {
switch
(
$feMode
)
{
case
FE_MODE_SHOW
:
case
FE_MODE_SHOW_REQUIRED
:
break
;
case
FE_MODE_REQUIRED
:
$required
=
'yes'
;
...
...
@@ -1679,7 +1677,6 @@ abstract class AbstractBuildForm {
switch
(
$feMode
)
{
case
FE_MODE_HIDDEN
:
case
FE_MODE_SHOW
:
case
FE_MODE_SHOW_REQUIRED
:
break
;
case
FE_MODE_REQUIRED
:
case
FE_MODE_READONLY
:
...
...
extension/Classes/Core/BuildFormBootstrap.php
View file @
2e0e3a4d
...
...
@@ -593,6 +593,15 @@ class BuildFormBootstrap extends AbstractBuildForm {
$attribute
[
'class'
]
=
'form-horizontal'
;
$attribute
[
'data-toggle'
]
=
'validator'
;
$formModeGlobal
=
$this
->
store
::
getVar
(
F_MODE_GLOBAL
,
STORE_SIP
.
STORE_EMPTY
);
if
(
$formModeGlobal
==
''
)
{
$formModeGlobal
=
$this
->
formSpec
[
F_MODE_GLOBAL
]
??
''
;
}
if
(
$formModeGlobal
==
F_MODE_SKIP_REQUIRED_CHECK
||
$formModeGlobal
==
F_MODE_REQUIRED_OFF
)
{
$attribute
[
DATA_SKIP_REQUIRED_CHECK
]
=
'true'
;
}
if
(
isset
(
$this
->
formSpec
[
F_SAVE_BUTTON_ACTIVE
])
&&
$this
->
formSpec
[
F_SAVE_BUTTON_ACTIVE
]
!=
'0'
)
{
$attribute
[
DATA_ENABLE_SAVE_BUTTON
]
=
'true'
;
}
...
...
@@ -794,7 +803,7 @@ EOF;
}
}
if
(
$formElement
[
FE_MODE
]
==
FE_MODE_REQUIRED
||
$formElement
[
FE_MODE
]
==
FE_MODE_SHOW_REQUIRED
)
{
if
(
$formElement
[
FE_MODE
]
==
FE_MODE_REQUIRED
)
{
$addClassRequired
=
HelperFormElement
::
getRequiredPositionClass
(
$formElement
[
F_FE_REQUIRED_POSITION
]);
}
...
...
extension/Classes/Core/Constants.php
View file @
2e0e3a4d
...
...
@@ -723,6 +723,7 @@ const VAR_FILENAME_BASE = 'filenameBase'; // Original filename of an uploaded fi
const
VAR_FILENAME_EXT
=
'filenameExt'
;
// Extension of the original filename of an uploaded file, .
const
VAR_FILE_MIME_TYPE
=
'mimeType'
;
const
VAR_FILE_SIZE
=
'fileSize'
;
const
VAR_ALL_REQUIRED_GIVEN
=
'allRequiredGiven'
;
// 0 if at least one FE is required and value is missing, else 1.
// PHP class Typeahead
...
...
@@ -835,6 +836,8 @@ const API_ANSWER_REDIRECT_URL_SKIP_HISTORY = 'url-skip-history';
const
API_TYPEAHEAD_KEY
=
'key'
;
const
API_TYPEAHEAD_VALUE
=
'value'
;
const
DATA_SKIP_REQUIRED_CHECK
=
'data-skip-required-check'
;
const
DATA_HIDDEN
=
'data-hidden'
;
const
DATA_DISABLED
=
'data-disabled'
;
const
DATA_REQUIRED
=
'data-required'
;
...
...
@@ -1007,7 +1010,8 @@ const F_TYPEAHEAD_LDAP_SEARCH_PER_TOKEN = 'typeAheadLdapSearchPerToken';
const
F_MODE
=
'mode'
;
const
F_MODE_READONLY
=
'readonly'
;
const
F_MODE_REQUIRED_OFF
=
'requiredOff'
;
const
F_MODE_REQUIRED_OFF
=
'requiredOff'
;
// deprecated, #9617
const
F_MODE_SKIP_REQUIRED_CHECK
=
'skipRequiredCheck'
;
const
F_MODE_GLOBAL
=
'formModeGlobal'
;
const
F_SAVE_BUTTON_ACTIVE
=
'saveButtonActive'
;
...
...
@@ -1059,7 +1063,6 @@ const CLIENT_REST_FORM = '_form';
const
FE_MODE_SHOW
=
'show'
;
const
FE_MODE_READONLY
=
'readonly'
;
const
FE_MODE_REQUIRED
=
'required'
;
const
FE_MODE_SHOW_REQUIRED
=
'showRequired'
;
const
FE_MODE_HIDDEN
=
'hidden'
;
const
FE_CLASS_NATIVE
=
'native'
;
...
...
extension/Classes/Core/Helper/HelperFormElement.php
View file @
2e0e3a4d
...
...
@@ -408,7 +408,7 @@ EOF;
EOF;
}
$skip
=
(
!
(
$formElement
[
FE_MODE
]
==
FE_MODE_SHOW
||
$formElement
[
FE_MODE
]
==
FE_MODE_REQUIRED
||
$formElement
[
FE_MODE
]
==
FE_MODE_SHOW_REQUIRED
));
$skip
=
(
!
(
$formElement
[
FE_MODE
]
==
FE_MODE_SHOW
||
$formElement
[
FE_MODE
]
==
FE_MODE_REQUIRED
));
// LOCK
if
(
!
$skip
&&
HelperFormElement
::
booleParameter
(
$formElement
[
FE_INPUT_EXTRA_BUTTON_LOCK
]
??
'-'
))
{
...
...
@@ -532,4 +532,5 @@ EOF;
public
static
function
booleParameter
(
$data
)
{
return
$data
==
''
||
$data
==
'1'
;
}
}
\ No newline at end of file
extension/Classes/Core/Helper/Support.php
View file @
2e0e3a4d
...
...
@@ -1171,8 +1171,6 @@ class Support {
case
FE_MODE_REQUIRED
:
if
(
$formMode
==
F_MODE_READONLY
)
{
$feMode
=
FE_MODE_READONLY
;
}
elseif
(
$formMode
==
F_MODE_REQUIRED_OFF
&&
$feMode
==
FE_MODE_REQUIRED
)
{
$feMode
=
FE_MODE_SHOW_REQUIRED
;
}
break
;
...
...
extension/Classes/Core/Save.php
View file @
2e0e3a4d
...
...
@@ -544,10 +544,17 @@ class Save {
*/
public
function
checkRequiredHidden
()
{
$requiredOff
=
(
$this
->
store
->
getVar
(
F_MODE_GLOBAL
,
STORE_SIP
)
==
F_MODE_REQUIRED_OFF
);
$formModeGlobal
=
$this
->
store
->
getVar
(
F_MODE_GLOBAL
,
STORE_SIP
.
STORE_EMPTY
);
if
(
$formModeGlobal
==
''
)
{
$formModeGlobal
=
$this
->
formSpec
[
F_MODE_GLOBAL
]
??
''
;
}
$reportRequiredFailed
=
(
$formModeGlobal
!=
F_MODE_REQUIRED_OFF
&&
$formModeGlobal
!=
F_MODE_SKIP_REQUIRED_CHECK
);
$clientValues
=
$this
->
store
::
getStore
(
STORE_FORM
);
$flagAllRequiredGiven
=
1
;
foreach
(
$this
->
feSpecNative
AS
$key
=>
$formElement
)
{
// Do not check retype slave FE.
...
...
@@ -569,8 +576,11 @@ class Save {
$mode
=
'fake'
;
// The next if() should never be true.
}
if
(
!
$requiredOff
&&
$mode
==
FE_MODE_REQUIRED
&&
empty
(
$clientValues
[
$formElement
[
FE_NAME
]]))
{
throw
new
\
UserFormException
(
"Missing required value: "
.
$formElement
[
FE_LABEL
],
ERROR_REQUIRED_VALUE_EMPTY
);
if
(
$mode
==
FE_MODE_REQUIRED
&&
empty
(
$clientValues
[
$formElement
[
FE_NAME
]]))
{
$flagAllRequiredGiven
=
0
;
if
(
$reportRequiredFailed
)
{
throw
new
\
UserFormException
(
"Missing required value: "
.
$formElement
[
FE_LABEL
],
ERROR_REQUIRED_VALUE_EMPTY
);
}
}
if
(
$mode
==
FE_MODE_HIDDEN
)
{
...
...
@@ -578,6 +588,9 @@ class Save {
$this
->
store
::
unsetVar
(
$formElement
[
FE_NAME
],
STORE_FORM
);
}
}
// Save 'allRequiredGiven in STORE_VAR
$this
->
store
::
setVar
(
VAR_ALL_REQUIRED_GIVEN
,
$flagAllRequiredGiven
,
STORE_VAR
,
true
);
}
/**
...
...
extension/Classes/Core/Store/FillStoreForm.php
View file @
2e0e3a4d
...
...
@@ -184,7 +184,7 @@ class FillStoreForm {
if
(
$formMode
==
FORM_UPDATE
&&
$formModeGlobal
==
''
)
{
# During 'update': fake all elements to be not 'required'.
$formModeGlobal
=
F_MODE_REQUIRED_
OFF
;
$formModeGlobal
=
F_MODE_
SKIP_
REQUIRED_
CHECK
;
}
// If called through 'api/...': get STORE_TYPO3 via SIP parameter.
...
...
@@ -289,7 +289,6 @@ class FillStoreForm {
if
(
$formElement
[
FE_DYNAMIC_UPDATE
]
===
'yes'
||
$formElement
[
FE_MODE
]
===
FE_MODE_REQUIRED
||
$formElement
[
FE_MODE
]
===
FE_MODE_SHOW_REQUIRED
||
$formElement
[
FE_MODE
]
===
FE_MODE_SHOW
||
(
isset
(
$formElement
[
FE_PROCESS_READ_ONLY
])
&&
$formElement
[
FE_PROCESS_READ_ONLY
]
!=
'0'
))
{
...
...
javascript/src/QfqForm.js
View file @
2e0e3a4d
...
...
@@ -67,6 +67,12 @@ var QfqNS = QfqNS || {};
this
.
form
=
new
n
.
Form
(
this
.
formId
,
false
);
}
if
(
$
(
'
#
'
+
QfqNS
.
escapeJqueryIdSelector
(
this
.
formId
)).
data
(
'
skip-required-check
'
))
{
this
.
skipRequiredCheck
=
true
;
}
else
{
this
.
skipRequiredCheck
=
false
;
}
this
.
infoLockedButton
=
this
.
infoLockedButton
.
bind
(
this
);
// This is required when displaying validation messages, in order to activate the tab, which has validation
...
...
@@ -622,12 +628,17 @@ var QfqNS = QfqNS || {};
alert
=
new
n
.
Alert
(
"
Form is incomplete.
"
,
"
warning
"
);
alert
.
timeout
=
3000
;
alert
.
show
();
return
;
if
(
!
this
.
skipRequiredCheck
)
{
return
;
}
}
// First, remove all validation states, in case a previous submit has set a validation state, thus we're not
// stockpiling them.
this
.
clearAllValidationStates
();
if
(
!
this
.
skipRequiredCheck
)
{
this
.
clearAllValidationStates
();
}
submitReason
=
{
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment