[TASK] EXT:form - optimize DatePicker element 61/51461/8
authorRalf Zimmermann <ralf.zimmermann@tritum.de>
Sun, 29 Jan 2017 23:12:35 +0000 (00:12 +0100)
committerChristian Kuhn <lolli@schwarzbu.ch>
Sun, 5 Feb 2017 22:23:24 +0000 (23:23 +0100)
* add more configuration options to the DatePicker element
  within the form editor
* render the frontend JavaScript as inline JavaScript within the page
  footer
* fix small bugs

Resolves: #79539
Releases: master
Change-Id: I7a33abbc3502dbad37e228313b93e32ae5b19bf5
Reviewed-on: https://review.typo3.org/51461
Tested-by: TYPO3com <no-reply@typo3.com>
Tested-by: Andreas Steiger <typo3@andreassteiger.de>
Reviewed-by: Bjoern Jacob <bjoern.jacob@tritum.de>
Tested-by: Bjoern Jacob <bjoern.jacob@tritum.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/form/Classes/ViewHelpers/Form/DatePickerViewHelper.php
typo3/sysext/form/Classes/ViewHelpers/Form/TimePickerViewHelper.php
typo3/sysext/form/Configuration/Yaml/BaseSetup.yaml
typo3/sysext/form/Configuration/Yaml/FormEditorSetup.yaml
typo3/sysext/form/Resources/Private/Frontend/Partials/DatePicker.html
typo3/sysext/form/Resources/Private/Language/Database.xlf
typo3/sysext/form/Resources/Private/Language/locallang.xlf
typo3/sysext/form/Resources/Public/JavaScript/Backend/FormEditor/StageComponent.js

index ad27cde..3d81be8 100644 (file)
@@ -17,8 +17,11 @@ namespace TYPO3\CMS\Form\ViewHelpers\Form;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Page\PageRenderer;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Property\PropertyMapper;
 use TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFieldViewHelper;
+use TYPO3\CMS\Form\ViewHelpers\RenderRenderableViewHelper;
 
 /**
  * Display a jQuery date picker.
@@ -65,6 +68,7 @@ class DatePickerViewHelper extends AbstractFormFieldViewHelper
         $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('previewMode', 'bool', 'Preview mde flag', true, false);
         $this->registerArgument('dateFormat', 'string', 'The date format', false, 'Y-m-d');
         $this->registerUniversalTagAttributes();
     }
@@ -79,37 +83,44 @@ class DatePickerViewHelper extends AbstractFormFieldViewHelper
     {
         $enableDatePicker = $this->arguments['enableDatePicker'];
         $dateFormat = $this->arguments['dateFormat'];
+        $previewMode = (bool)$this->arguments['previewMode'];
+        $placeholder = $this->arguments['placeholder'];
 
         $name = $this->getName();
         $this->registerFieldNameForFormTokenGeneration($name);
 
-        $this->tag->addAttribute('type', 'date');
+        $this->tag->addAttribute('type', 'input');
         $this->tag->addAttribute('name', $name . '[date]');
+
+        if ($this->hasArgument('id')) {
+            $id = $this->arguments['id'];
+        } else {
+            $id = 'field' . md5(uniqid());
+        }
+
+        if (empty($placeholder)) {
+            $this->tag->addAttribute('placeholder', $dateFormat);
+        }
+
         if ($enableDatePicker) {
             $this->tag->addAttribute('readonly', true);
+            if (!$previewMode) {
+                $datePickerDateFormat = $this->convertDateFormatToDatePickerFormat($dateFormat);
+                $this->renderInlineJavascript($id, $datePickerDateFormat);
+            }
         }
         $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->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->renderingContext->getVariableProvider()->add('datePickerDateFormat', $datePickerDateFormat);
-            $content .= $this->renderChildren();
-            $this->renderingContext->getVariableProvider()->remove('datePickerDateFormat');
-        }
         return $content;
     }
 
@@ -163,4 +174,37 @@ class DatePickerViewHelper extends AbstractFormFieldViewHelper
         ];
         return strtr($dateFormat, $replacements);
     }
+
+    /**
+     * @param string $uniqueIdentifier
+     * @param string $datePickerDateFormat
+     * @return void
+     */
+    protected function renderInlineJavascript(string $uniqueIdentifier, string $datePickerDateFormat)
+    {
+        $this->getPageRenderer()->addJsFooterInlineCode(
+            'ext_form_datepicker-' . $uniqueIdentifier,
+            'if ("undefined" !== typeof $) {
+                    $(function() {
+                        $("#' . $uniqueIdentifier . '").datepicker({
+                            dateFormat: "' . $datePickerDateFormat . '"
+                        }).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);
+                            }
+                        });
+                    });
+                }
+            ');
+    }
+
+    /**
+     * @return PageRenderer
+     */
+    protected function getPageRenderer(): PageRenderer
+    {
+        return GeneralUtility::makeInstance(PageRenderer::class);
+    }
 }
index 558afa9..4c5003f 100644 (file)
@@ -64,6 +64,7 @@ class TimePickerViewHelper extends AbstractFormFieldViewHelper
         $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->registerArgument('timeType', 'string', '"hour" or "minute"');
         $this->registerUniversalTagAttributes();
     }
 
@@ -77,14 +78,19 @@ class TimePickerViewHelper extends AbstractFormFieldViewHelper
     {
         $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);
+
+        if ($this->arguments['timeType'] === 'hour') {
+            $content .= $this->buildHourSelector($date);
+        } else {
+            $content .= $this->buildMinuteSelector($date);
+        }
+
         return $content;
     }
 
index 252b6b9..736b978 100644 (file)
@@ -117,8 +117,10 @@ TYPO3:
                 10: 'TYPO3.CMS.Form.mixins.formElementMixins.FormElementMixin'
               implementationClassName: 'TYPO3\CMS\Form\Domain\Model\FormElements\DatePicker'
               properties:
-                elementClassAttribute: 'small'
+                elementClassAttribute: 'small form-control'
                 timeSelectorClassAttribute: 'mini'
+                timeSelectorHourLabel: ''
+                timeSelectorMinuteLabel: ''
                 dateFormat: 'Y-m-d'
                 enableDatePicker: true
                 displayTimeSelector: false
index 81046ef..efae3d9 100644 (file)
@@ -415,8 +415,28 @@ TYPO3:
                 label: 'formEditor.elements.DatePicker.label'
                 group: custom
                 groupSorting: 100
+                predefinedDefaults:
+                  properties:
+                    dateFormat: 'Y-m-d'
+                    enableDatePicker: true
+                    displayTimeSelector: false
                 iconIdentifier: 't3-form-icon-date-picker'
                 editors:
+                  300:
+                    identifier: 'dateFormat'
+                    templateName: 'Inspector-TextEditor'
+                    label: 'formEditor.elements.DatePicker.editor.dateFormat.label'
+                    propertyPath: 'properties.dateFormat'
+                  400:
+                    identifier: 'enableDatePicker'
+                    templateName: 'Inspector-CheckboxEditor'
+                    label: 'formEditor.elements.DatePicker.editor.enableDatePicker.label'
+                    propertyPath: 'properties.enableDatePicker'
+                  500:
+                    identifier: 'displayTimeSelector'
+                    templateName: 'Inspector-CheckboxEditor'
+                    label: 'formEditor.elements.DatePicker.editor.displayTimeSelector.label'
+                    propertyPath: 'properties.displayTimeSelector'
                   900:
                     identifier: 'validators'
                     templateName: 'Inspector-ValidatorsEditor'
index e4687e5..eb784f3 100644 (file)
@@ -1,48 +1,48 @@
 {namespace formvh=TYPO3\CMS\Form\ViewHelpers}
 <formvh:renderRenderable renderable="{element}">
-    <f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
-        <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"
+    <div class="form-inline">
+            <f:render partial="Field/Field" arguments="{element: element}" contentAs="elementContent">
+                <formvh:form.datePicker
+                    id="{element.uniqueIdentifier}"
                     property="{element.identifier}"
+                    placeholder="{formvh:translateElementProperty(element: element, property: 'placeholder')}"
+                    dateFormat="{element.properties.dateFormat}"
                     initialDate="{element.properties.initialDate}"
-                    class="{element.properties.timeSelectorClassAttribute} form-control"
+                    enableDatePicker="{element.properties.enableDatePicker}"
+                    class="{element.properties.elementClassAttribute}"
                     errorClass="{element.properties.elementErrorClassAttribute}"
-            />
-        </f:if>
-    </f:render>
+                    additionalAttributes="{f:if(condition: '{element.required}', then: '{required: \'required\'}')}"
+                    previewMode="{element.rootForm.renderingOptions.previewMode}"
+                />
+            </f:render>
+
+        <f:if condition="{element.properties.displayTimeSelector}">
+            <div class="form-group{f:if(condition: '{validationResults.errors.0}', then: ' has-error')}">
+                <label class="control-label" for="{element.uniqueIdentifier}-time">{formvh:translateElementProperty(element: element, property: 'timeSelectorHourLabel')}</label>
+                <div class="{element.properties.containerClassAttribute}">
+                    <formvh:form.timePicker
+                            id="{element.uniqueIdentifier}-time"
+                            property="{element.identifier}"
+                            initialDate="{element.properties.initialDate}"
+                            class="{element.properties.timeSelectorClassAttribute} form-control"
+                            errorClass="{element.properties.elementErrorClassAttribute}"
+                            timeType="hour"
+                    />
+                </div>
+            </div>
+            <div class="form-group{f:if(condition: '{validationResults.errors.0}', then: ' has-error')}">
+                <label class="control-label" for="{element.uniqueIdentifier}-time-minute">{formvh:translateElementProperty(element: element, property: 'timeSelectorMinuteLabel')}</label>
+                <div class="{element.properties.containerClassAttribute}">
+                    <formvh:form.timePicker
+                            id="{element.uniqueIdentifier}-time"
+                            property="{element.identifier}"
+                            initialDate="{element.properties.initialDate}"
+                            class="{element.properties.timeSelectorClassAttribute} form-control"
+                            errorClass="{element.properties.elementErrorClassAttribute}"
+                            timeType="minute"
+                    />
+                </div>
+            </div>
+         </f:if>
+    </div>
 </formvh:renderRenderable>
\ No newline at end of file
index 6421717..48679d2 100644 (file)
             <trans-unit id="formEditor.elements.DatePicker.label" xml:space="preserve">
                 <source>Date picker</source>
             </trans-unit>
+            <trans-unit id="formEditor.elements.DatePicker.editor.dateFormat.label" xml:space="preserve">
+                <source>Date format</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.DatePicker.editor.enableDatePicker.label" xml:space="preserve">
+                <source>Enable datepicker (needs jQuery UI)</source>
+            </trans-unit>
+            <trans-unit id="formEditor.elements.DatePicker.editor.displayTimeSelector.label" xml:space="preserve">
+                <source>Display time selector</source>
+            </trans-unit>
             <trans-unit id="formEditor.elements.DatePicker.editor.validators.label" xml:space="preserve">
                 <source>Validators</source>
             </trans-unit>
index f7fe933..b524e1c 100644 (file)
             <trans-unit id="element.ImageUpload.properties.SummaryPage.altText" xml:space="preserve">
                 <source>uploaded image</source>
             </trans-unit>
+            <trans-unit id="element.DatePicker.properties.timeSelectorHourLabel" xml:space="preserve">
+                <source>Hour</source>
+            </trans-unit>
+            <trans-unit id="element.DatePicker.properties.timeSelectorMinuteLabel" xml:space="preserve">
+                <source>Minute</source>
+            </trans-unit>
 
             <trans-unit id="validation.error.1221560910" xml:space="preserve">
                 <source>This field is mandatory</source>
index e843a75..789f567 100644 (file)
@@ -253,12 +253,12 @@ define(['jquery',
                 case 'AdvancedPassword':
                 case 'Password':
                 case 'Text':
+                case 'DatePicker':
                     renderSimpleTemplateWithValidators(formElement, template);
                     break;
                 case 'Fieldset':
                 case 'SummaryPage':
                 case 'Page':
-                case 'DatePicker':
                 case 'StaticText':
                 case 'Hidden':
                 case 'ContentElement':