[TASK] Move FormEngine SelectboxFilter to jQuery 12/34212/2
authorBenjamin Mack <benni@typo3.org>
Sat, 15 Nov 2014 17:05:14 +0000 (18:05 +0100)
committerFrank Nägler <typo3@naegler.net>
Sat, 15 Nov 2014 21:34:16 +0000 (22:34 +0100)
One of the last bits and pieces with PrototypeJS
is a relatively new feature introduced with 6.2
for filtering records in a multi-select (two boxes mode).

The JS functionality was completely written,
styling is optimized to fit bootstrap needs.

Through using deferred event handlers, the
PHP code is reduced.

Releases: master
Resolves: #62991
Change-Id: Idb189a871b8499fd5129773641f6ac5e8fb373d2
Reviewed-on: http://review.typo3.org/34212
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
Reviewed-by: Frank Nägler <typo3@naegler.net>
Tested-by: Frank Nägler <typo3@naegler.net>
typo3/sysext/backend/Classes/Form/Element/SelectElement.php
typo3/sysext/backend/Classes/Form/FormEngine.php
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine.js
typo3/sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_selectboxfilter.js [deleted file]
typo3/sysext/t3skin/Resources/Private/Styles/TYPO3/_element_tceforms.less
typo3/sysext/t3skin/Resources/Public/Css/visual/t3skin.css

index cbd325a..24dc62d 100644 (file)
@@ -187,20 +187,12 @@ class SelectElement extends AbstractFormElement {
                                        ', $opt) . '
                                </select>';
 
-                       if ($config['enableMultiSelectFilterTextfield'] || $config['multiSelectFilterItems']) {
-                               $this->formEngine->multiSelectFilterCount++;
-                               $jsSelectBoxFilterName = str_replace(' ', '', ucwords(str_replace('-', ' ', GeneralUtility::strtolower($multiSelectId))));
-                               $this->formEngine->additionalJS_post[] = '
-                                       var ' . $jsSelectBoxFilterName . ' = new TCEForms.SelectBoxFilter("' . $multiSelectId . '");
-                               ';
-                       }
-
+                       // enable filter functionality via a text field
                        if ($config['enableMultiSelectFilterTextfield']) {
-                               // add input field for filter
-                               $filterTextfield = '<input class="typo3-TCEforms-suggest-search typo3-TCEforms-multiselect-filter" id="'
-                                       . $multiSelectId . '_filtertextfield" value="" style="width: 104px;" />';
+                               $filterTextfield = '<span class="input-group"><span class="input-group-addon"><span class="fa fa-filter"></span></span><input class="t3-form-multiselect-filter-textfield form-control" value="" /></span>';
                        }
 
+                       // enable filter functionality via a select
                        if (isset($config['multiSelectFilterItems']) && is_array($config['multiSelectFilterItems']) && count($config['multiSelectFilterItems']) > 1) {
                                $filterDropDownOptions = array();
                                foreach ($config['multiSelectFilterItems'] as $optionElement) {
@@ -209,13 +201,18 @@ class SelectElement extends AbstractFormElement {
                                        $filterDropDownOptions[] = '<option value="' . htmlspecialchars($this->formEngine->sL($optionElement[0])) . '">'
                                                . htmlspecialchars($optionValue) . '</option>';
                                }
-                               $filterSelectbox = '
-                                       <select id="' . $multiSelectId . '_filterdropdown">
+                               $filterSelectbox = '<select class="t3-form-multiselect-filter-dropdown form-control">
                                                ' . implode('
                                                ', $filterDropDownOptions) . '
                                        </select>';
                        }
                }
+
+               $selectBoxFilterContents = trim($filterSelectbox . $filterTextfield);
+               if (!empty($selectBoxFilterContents)) {
+                       $selectBoxFilterContents = '<div class="form-inline"><div class="t3-form-multiselect-filter-container form-group-sm pull-right">' . $selectBoxFilterContents . '</div></div>';
+               }
+
                // Pass to "dbFileIcons" function:
                $params = array(
                        'size' => $size,
@@ -228,7 +225,7 @@ class SelectElement extends AbstractFormElement {
                        'info' => '',
                        'headers' => array(
                                'selector' => $this->formEngine->getLL('l_selected') . ':<br />',
-                               'items' => $this->formEngine->getLL('l_items') . ': ' . $filterSelectbox . $filterTextfield . '<br />'
+                               'items' => '<div class="pull-left">' . $this->formEngine->getLL('l_items') . ':</div>' . $selectBoxFilterContents
                        ),
                        'noBrowser' => 1,
                        'thumbnails' => $itemsToSelect,
index f69898f..b88ca70 100644 (file)
@@ -636,12 +636,6 @@ class FormEngine {
         */
        public $templateFile = '';
 
-       /**
-        * @var int
-        * @internal
-        */
-       public $multiSelectFilterCount = 0;
-
        /**
         * @var \TYPO3\CMS\Backend\Form\Element\SuggestElement
         */
@@ -3982,24 +3976,14 @@ class FormEngine {
                                ';
                                // Always include JS functions for Suggest fields as we don't know what will come
                                $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_suggest.js');
-                               $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_selectboxfilter.js');
                        } else {
                                // If Suggest fields were processed, add the JS functions
                                if ($this->suggest->suggestCount > 0) {
                                        $pageRenderer->loadScriptaculous();
                                        $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_suggest.js');
                                }
-                               if ($this->multiSelectFilterCount > 0) {
-                                       $pageRenderer->loadScriptaculous();
-                                       $this->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_selectboxfilter.js');
-                               }
                        }
                        $out .= '
-                       function getOuterHTML(idTagPrefix) {    // Function getting the outerHTML of an element with id
-                               var str=($(idTagPrefix).inspect()+$(idTagPrefix).innerHTML+"</"+$(idTagPrefix).tagName.toLowerCase()+">");
-                               return str;
-                       }
-
                        TBE_EDITOR.images.req.src = "' . IconUtility::skinImg($this->backPath, 'gfx/required_h.gif', '', 1) . '";
                        TBE_EDITOR.images.cm.src = "' . IconUtility::skinImg($this->backPath, 'gfx/content_client.gif', '', 1) . '";
                        TBE_EDITOR.images.sel.src = "' . IconUtility::skinImg($this->backPath, 'gfx/content_selected.gif', '', 1) . '";
index b579648..d22475f 100644 (file)
@@ -559,12 +559,73 @@ define('TYPO3/CMS/Backend/FormEngine', ['jquery'], function ($) {
                });
        };
 
+       /**
+        * select field filter functions, see TCA option "enableMultiSelectFilterTextfield"
+        * and "multiSelectFilterItems"
+        */
+       FormEngine.SelectBoxFilter = {
+               options: {
+                       fieldContainerSelector: '.t3-form-field-group-file',
+                       filterContainerSelector: '.t3-form-multiselect-filter-container',
+                       filterTextFieldSelector: '.t3-form-multiselect-filter-textfield',
+                       filterSelectFieldSelector: '.t3-form-multiselect-filter-dropdown',
+                       itemsToSelectElementSelector: '.t3-form-select-itemstoselect'
+               }
+       };
 
+       /**
+        * make sure that all selectors and input filters are recognized
+        */
+       FormEngine.SelectBoxFilter.initializeEvents = function() {
+               $(document).on('keyup', FormEngine.SelectBoxFilter.options.filterTextFieldSelector, function() {
+                       var $selectElement = FormEngine.SelectBoxFilter.getSelectElement($(this));
+                       FormEngine.SelectBoxFilter.filter($selectElement, $(this).val());
+               }).on('change', FormEngine.SelectBoxFilter.options.filterSelectFieldSelector, function() {
+                       var $selectElement = FormEngine.SelectBoxFilter.getSelectElement($(this));
+                       FormEngine.SelectBoxFilter.filter($selectElement, $(this).val());
+               });
+       };
 
-       // initialize function, always require possible post-render hooks return the main object
-       var initializeModule = function(options) {
+       /**
+        * fetch the "itemstoselect" select element where a filter item is attached to
+        */
+       FormEngine.SelectBoxFilter.getSelectElement = function($relativeElement) {
+               var $containerElement = $relativeElement.closest(FormEngine.SelectBoxFilter.options.fieldContainerSelector);
+               return $containerElement.find(FormEngine.SelectBoxFilter.options.itemsToSelectElementSelector);
+       };
 
+       /**
+        * filter the actual items
+        */
+       FormEngine.SelectBoxFilter.filter = function($selectElement, filterText) {
+               var $allOptionElements;
+               if (!$selectElement.data('alloptions')) {
+                       $allOptionElements = $selectElement.find('option').clone();
+                       $selectElement.data('alloptions', $allOptionElements);
+               } else {
+                       $allOptionElements = $selectElement.data('alloptions');
+               }
+
+               if (filterText.length > 0) {
+                       var matchFilter = new RegExp(filterText, 'i');
+                       $selectElement.html('');
+                       $allOptionElements.each(function() {
+                               if ($(this).text().match(matchFilter)) {
+                                       $selectElement.append($(this).clone());
+                               }
+                       });
+               } else {
+                       $selectElement.html($allOptionElements);
+               }
+       };
+
+
+       /**
+        * initialize function, always require possible post-render hooks return the main object
+        */
+       return function() {
                FormEngine.initializeEvents();
+               FormEngine.SelectBoxFilter.initializeEvents();
 
                // load required modules to hook in the post initialize function
                if (undefined !== TYPO3.settings.RequireJS && undefined !== TYPO3.settings.RequireJS.PostInitializationModules['TYPO3/CMS/Backend/FormEngine']) {
@@ -578,8 +639,5 @@ define('TYPO3/CMS/Backend/FormEngine', ['jquery'], function ($) {
 
                // return the object in the global space
                return FormEngine;
-       };
-
-       // call the main initialize function and execute the hooks
-       return initializeModule();
+       }();
 });
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_selectboxfilter.js b/typo3/sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_selectboxfilter.js
deleted file mode 100644 (file)
index e35dbe0..0000000
+++ /dev/null
@@ -1,106 +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!
- */
-
-/**
- * Class for JS handling of selectbox filter in TCEforms.
- *
- * @author  Marc Bastian Heinrichs <mbh@mbh-software.de>
- */
-
-if (!TCEForms) {
-       var TCEForms = {};
-}
-
-TCEForms.SelectBoxFilter = Class.create({
-       selectBox: '',
-       selectBoxOriginal: '',
-       selectBoxOriginalOptionsLength: 0,
-       filterTextfield: false,
-       filterDropDown: false,
-       delayObject: '',
-
-       /**
-        * Assigns a new filter object to the available items select box object.
-        *
-        * @param selectBoxId  The ID of the object to assign the filter to
-        */
-       initialize: function(selectBoxId) {
-
-               this.selectBox = $(selectBoxId);
-               this.selectBoxOriginal = this.selectBox.cloneNode(true);
-               this.selectBoxOriginalOptionsLength = this.selectBoxOriginal.options.length;
-
-               if ($(selectBoxId + '_filtertextfield') != undefined) {
-                       this.filterTextfield = $(selectBoxId + '_filtertextfield');
-               }
-               if ($(selectBoxId + '_filterdropdown') != undefined) {
-                       this.filterDropDown = $(selectBoxId + '_filterdropdown');
-               }
-
-               // setting
-               if (this.filterTextfield) {
-                       this.filterTextfield.observe('keyup', function(event) {
-                               this.delayObject = this.updateSelectOptions.bindAsEventListener(this).delay(0.5);
-                       }.bindAsEventListener(this));
-
-                       this.filterTextfield.observe('keydown', function(event) {
-                       if (this.delayObject != undefined)
-                               window.clearTimeout(this.delayId);
-                       }.bindAsEventListener(this));
-               }
-
-               if (this.filterDropDown) {
-                       this.filterDropDown.observe('change', function(event) {
-                               this.updateSelectOptions();
-                       }.bindAsEventListener(this));
-               }
-       },
-
-       /**
-        * Updates the available items select box based the filter textfield or filter drop-down
-        */
-       updateSelectOptions: function() {
-
-               var filterTextFromTextfield = '';
-               var filterTextFromDropDown = '';
-
-               if (this.filterTextfield) {
-                       filterTextFromTextfield = this.filterTextfield.getValue();
-               }
-
-               if (this.filterDropDown) {
-                       filterTextFromDropDown = this.filterDropDown.getValue();
-               }
-
-               this.selectBox.innerHTML = '';
-
-               if (filterTextFromTextfield.length > 0 || filterTextFromDropDown.length > 0) {
-                       var matchStringTextfield = new RegExp(filterTextFromTextfield, 'i');
-                       var matchStringDropDown = new RegExp(filterTextFromDropDown, 'i');
-                       for (var i = 0; i < this.selectBoxOriginalOptionsLength; i++) {
-                               if (this.selectBoxOriginal.options[i].firstChild.nodeValue.match(matchStringTextfield) != null &&
-                                       this.selectBoxOriginal.options[i].firstChild.nodeValue.match(matchStringDropDown) != null) {
-                                       var tempNode = this.selectBoxOriginal.options[i].cloneNode(true);
-                                       this.selectBox.appendChild(tempNode);
-                               }
-                       }
-               } else {
-                       // recopy original list
-                       for (var i = 0; i < this.selectBoxOriginalOptionsLength; i++) {
-                               var tempNode = this.selectBoxOriginal.options[i].cloneNode(true);
-                               this.selectBox.appendChild(tempNode);
-                       }
-               }
-       }
-});
-
index 1f3f4db..b17dcc3 100644 (file)
@@ -307,6 +307,11 @@ div.typo3-TCEforms div.c-tablayer table > tbody > tr > td > table.wrapperTable >
        margin: 4px 2px 4px 1px;
 }
 
+.t3-form-multiselect-filter-textfield {
+       width: 60px;
+       padding-left: 25px;
+}
+
 .t3-form-palette-field-container {
        display: inline-block;
        vertical-align: top;
index e051f94..0e818d7 100644 (file)
@@ -9555,6 +9555,10 @@ div.typo3-TCEforms div.c-tablayer table > tbody > tr > td > table.wrapperTable >
 .t3-form-palette-field-container select.select {
   margin: 4px 2px 4px 1px;
 }
+.t3-form-multiselect-filter-textfield {
+  width: 80px;
+  padding-left: 25px;
+}
 .t3-form-palette-field-container {
   display: inline-block;
   vertical-align: top;