[FEATURE] Show link information below input field 79/51479/9
authorGeorg Ringer <georg.ringer@gmail.com>
Mon, 30 Jan 2017 22:25:56 +0000 (23:25 +0100)
committerAndreas Fernandez <typo3@scripting-base.de>
Mon, 6 Feb 2017 19:47:25 +0000 (20:47 +0100)
Render link information below a link field to help editors.
Instead of 't3://page?uid=92 _top "a class" "a title"' the user
will get relevant information.

Resolves: #28171
Releases: master
Change-Id: Ic285a10e1de67bf60dd5235885a8d0037792999a
Reviewed-on: https://review.typo3.org/51479
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Andreas Fernandez <typo3@scripting-base.de>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Andreas Fernandez <typo3@scripting-base.de>
typo3/sysext/backend/Classes/Form/Element/InputLinkElement.php
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine.js
typo3/sysext/backend/Resources/Public/JavaScript/jquery.clearable.js
typo3/sysext/core/Documentation/Changelog/master/Feature-28171-ImprovedLinkFieldInFormEngine.rst [new file with mode: 0644]

index 796d8d3..e66bca8 100644 (file)
@@ -16,9 +16,15 @@ namespace TYPO3\CMS\Backend\Form\Element;
 
 use TYPO3\CMS\Backend\Form\FieldWizard\DefaultLanguageDifferences;
 use TYPO3\CMS\Backend\Form\FieldWizard\OtherLanguageContent;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Imaging\Icon;
+use TYPO3\CMS\Core\LinkHandling\LinkService;
+use TYPO3\CMS\Core\Resource\File;
+use TYPO3\CMS\Core\Resource\Folder;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Core\Utility\StringUtility;
+use TYPO3\CMS\Frontend\Service\TypoLinkCodecService;
 use TYPO3\CMS\Lang\LanguageService;
 
 /**
@@ -123,6 +129,8 @@ class InputLinkElement extends AbstractFormElement
             'class' => implode(' ', [
                 'form-control',
                 't3js-clearable',
+                't3js-form-field-inputlink-input',
+                'hidden',
                 'hasDefaultValue',
             ]),
             'data-formengine-validation-rules' => $this->getValidationDataAsJsonString($config),
@@ -186,12 +194,23 @@ class InputLinkElement extends AbstractFormElement
         $fieldControlHtml = $legacyFieldControlHtml . $fieldControlResult['html'];
         $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false);
 
+        $linkExplanation = $this->getLinkExplanation($itemValue);
+
         $expansionHtml = [];
         $expansionHtml[] = '<div class="form-control-wrap" style="max-width: ' . $width . 'px">';
         $expansionHtml[] =  '<div class="form-wizards-wrap">';
         $expansionHtml[] =      '<div class="form-wizards-element">';
-        $expansionHtml[] =          '<input type="text"' . GeneralUtility::implodeAttributes($attributes, true) . ' />';
-        $expansionHtml[] =          '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '" value="' . htmlspecialchars($itemValue) . '" />';
+        $expansionHtml[] =          '<div class="input-group t3js-form-field-inputlink">';
+        $expansionHtml[] =              '<span class="input-group-addon">' . $linkExplanation['icon'] . '</span>';
+        $expansionHtml[] =              '<input class="form-control t3js-form-field-inputlink-explanation" disabled value="' . htmlspecialchars($linkExplanation['text']) . '">';
+        $expansionHtml[] =              '<input type="text"' . GeneralUtility::implodeAttributes($attributes, true) . ' />';
+        $expansionHtml[] =              '<span class="input-group-btn">';
+        $expansionHtml[] =                  '<button class="btn btn-default t3js-form-field-inputlink-explanation-toggle" type="button">';
+        $expansionHtml[] =                      $this->iconFactory->getIcon('actions-version-workspaces-preview-link', Icon::SIZE_SMALL)->render();
+        $expansionHtml[] =                  '</button>';
+        $expansionHtml[] =              '</span>';
+        $expansionHtml[] =              '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '" value="' . htmlspecialchars($itemValue) . '" />';
+        $expansionHtml[] =          '</div>';
         $expansionHtml[] =      '</div>';
         $expansionHtml[] =      '<div class="form-wizards-items-aside">';
         $expansionHtml[] =          '<div class="btn-group">';
@@ -200,6 +219,7 @@ class InputLinkElement extends AbstractFormElement
         $expansionHtml[] =          '</div>';
         $expansionHtml[] =      '</div>';
         $expansionHtml[] =      '<div class="form-wizards-items-bottom">';
+        $expansionHtml[] =          $linkExplanation['additionalAttributes'];
         $expansionHtml[] =          $fieldWizardHtml;
         $expansionHtml[] =      '</div>';
         $expansionHtml[] =  '</div>';
@@ -270,6 +290,97 @@ class InputLinkElement extends AbstractFormElement
     }
 
     /**
+     * @param string $itemValue
+     * @return array
+     */
+    protected function getLinkExplanation(string $itemValue): array
+    {
+        if (empty($itemValue)) {
+            return [];
+        }
+        $data = [];
+        $typolinkService = GeneralUtility::makeInstance(TypoLinkCodecService::class);
+        $linkParts = $typolinkService->decode($itemValue);
+        $linkService = GeneralUtility::makeInstance(LinkService::class);
+        $linkData = $linkService->resolve($linkParts['url']);
+        switch ($linkData['type']) {
+            case LinkService::TYPE_PAGE:
+                $pageRecord = BackendUtility::readPageAccess($linkData['pageuid'], '1=1');
+                // Is this a real page
+                if ($pageRecord['uid']) {
+                    $data = [
+                        'text' => htmlspecialchars($pageRecord['_thePathFull']) . '[' . $pageRecord['uid'] . ']',
+                        'icon' => $this->iconFactory->getIconForRecord('pages', $pageRecord, Icon::SIZE_SMALL)->render()
+                    ];
+                }
+                break;
+            case LinkService::TYPE_EMAIL:
+                $data = [
+                    'text' => htmlspecialchars($linkData['email']),
+                    'icon' => $this->iconFactory->getIcon('content-elements-mailform', Icon::SIZE_SMALL)->render()
+                ];
+                break;
+            case LinkService::TYPE_URL:
+                $data = [
+                    'text' => htmlspecialchars($linkData['url']),
+                    'icon' => $this->iconFactory->getIcon('apps-pagetree-page-shortcut-external', Icon::SIZE_SMALL)->render()
+
+                ];
+                break;
+            case LinkService::TYPE_FILE:
+                /** @var File $file */
+                $file = $linkData['file'];
+                if ($file) {
+                    $data = [
+                        'text' => htmlspecialchars($file->getPublicUrl()),
+                        'icon' => $this->iconFactory->getIconForFileExtension($file->getExtension(), Icon::SIZE_SMALL)->render()
+                    ];
+                }
+                break;
+            case LinkService::TYPE_FOLDER:
+                /** @var Folder $folder */
+                $folder = $linkData['folder'];
+                if ($folder) {
+                    $data = [
+                        'text' => htmlspecialchars($folder->getPublicUrl()),
+                        'icon' => $this->iconFactory->getIcon('apps-filetree-folder-default', Icon::SIZE_SMALL)->render()
+                    ];
+                }
+                break;
+            default:
+                $data = [
+                    'text' => htmlspecialchars('not implemented type ' . $linkData['type']),
+                    'icon' => ''
+                ];
+        }
+
+        $additionalAttributes = [];
+        unset($linkParts['url']);
+        foreach ($linkParts as $key => $value) {
+            if ($value) {
+                switch ($key) {
+                    case 'class':
+                        $label = $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_browse_links.xlf:class');
+                        break;
+                    case 'title':
+                        $label = $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_browse_links.xlf:title');
+                        break;
+                    case 'additionalParams':
+                        $label = $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_browse_links.xlf:params');
+                        break;
+                    default:
+                        $label = $key;
+                }
+
+                $additionalAttributes[] = '<span><strong>' . htmlspecialchars($label) . ': </strong> ' . htmlspecialchars($value) . '</span>';
+            }
+        }
+        $data['additionalAttributes'] = '<div class="help-block">' . implode(' - ', $additionalAttributes) . '</div>';
+
+        return $data;
+    }
+
+    /**
      * @return LanguageService
      */
     protected function getLanguageService()
index 659601f..51b1f92 100644 (file)
@@ -955,6 +955,29 @@ define(['jquery',
                FormEngine.convertTextareasEnableTab();
                FormEngine.initializeNullNoPlaceholderCheckboxes();
                FormEngine.initializeNullWithPlaceholderCheckboxes();
+               FormEngine.initializeInputLinkToggle();
+       };
+
+       /**
+        * Toggle for input link explanation
+        */
+       FormEngine.initializeInputLinkToggle = function () {
+               $(document).on('click', '.t3js-form-field-inputlink-explanation-toggle', function(e) {
+                       e.preventDefault();
+
+                       var $group = $(this).closest('.t3js-form-field-inputlink'),
+                               $inputField = $group.find('.t3js-form-field-inputlink-input'),
+                               $explanationField = $group.find('.t3js-form-field-inputlink-explanation'),
+                               explanationShown;
+
+                       explanationShown = !$explanationField.hasClass('hidden');
+                       $explanationField.toggleClass('hidden', explanationShown);
+                       $inputField.toggleClass('hidden', !explanationShown);
+                       $group.find('.form-control-clearable button.close').toggleClass('hidden', !explanationShown)
+               }).on('change', '.t3js-form-field-inputlink-input', function() {
+                       var $group = $(this).closest('.t3js-form-field-inputlink');
+                       $group.find('.t3js-form-field-inputlink-explanation, .t3js-form-field-inputlink-explanation-toggle').remove();
+               });
        };
 
        /**
index 833825c..812db1c 100644 (file)
                        // or the input field is a colorpicker, because it breaks the colorpicker.
                        if (!$input.data('clearable') && !$input.hasClass('t3js-color-picker')) {
                                $input.data('clearable', 'loaded');
+                               var hiddenClass = $input.hasClass('hidden') ? ' hidden' : '';
 
                                // Wrap it with a div and add a span that is the trigger for
                                // clearing.
                                $input.wrap('<div class="form-control-clearable" />');
-                               $input.after('<button type="button" class="close" tabindex="-1" aria-hidden="true"><span class="fa fa-times" /></button>');
+                               $input.after('<button type="button" class="close' + hiddenClass + '" tabindex="-1" aria-hidden="true"><span class="fa fa-times" /></button>');
                                $input.addClass('t3js-clearable');
 
                                var $clearer = $input.next();
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-28171-ImprovedLinkFieldInFormEngine.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-28171-ImprovedLinkFieldInFormEngine.rst
new file mode 100644 (file)
index 0000000..629afb4
--- /dev/null
@@ -0,0 +1,22 @@
+.. include:: ../../Includes.txt
+
+===================================================
+Feature: #28171 - Improved link field in FormEngine
+===================================================
+
+See :issue:`28171`
+
+Description
+===========
+
+The handling of link fields when managing records has been improved and now shows a speaking string,
+an icon and an additional help text instead of the cryptic :code:`t3://` syntaxt. This is enabled
+by default for all :code:`renderType="inputLink"` elements.
+
+
+Impact
+======
+
+Better UX of link fields in the Backend
+
+.. index:: Backend, TCA
\ No newline at end of file