[FEATURE] Add filter for available records in multi select element 71/24671/3
authorMarc Bastian Heinrichs <typo3@mbh-software.de>
Sun, 13 Oct 2013 09:58:14 +0000 (11:58 +0200)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Sun, 13 Oct 2013 12:49:38 +0000 (14:49 +0200)
This patch adds the possibility to filter available items in a multi
select element. By TCA settings you could enable a text field for
individual word filter and you could predefine search words the user
can select in a drop down.

Resolves: #49739
Releases: 6.2
Change-Id: I7112d10009da01a68c8e883719e2f4cee5201002
Reviewed-on: https://review.typo3.org/24671
Reviewed-by: Alexander Opitz
Tested-by: Alexander Opitz
Reviewed-by: Anja Leichsenring
Tested-by: Anja Leichsenring
typo3/sysext/backend/Classes/Form/FormEngine.php
typo3/sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_selectboxfilter.js [new file with mode: 0644]

index 2a3c70e..e4adbb2 100644 (file)
@@ -559,6 +559,11 @@ class FormEngine {
 
        public $templateFile = '';
 
+       /**
+        * @var int
+        */
+       protected $multiSelectFilterCount = 0;
+
        // Form templates, relative to typo3 directory
        /**
         * Constructor function, setting internal variables, loading the styles used.
@@ -2265,6 +2270,8 @@ function ' . $evalData . '(value) {
                        $itemArray[$tk] = implode('|', $tvP);
                }
                $itemsToSelect = '';
+               $filterTextfield = '';
+               $filterSelectbox = '';
                if (!$disabled) {
                        // Create option tags:
                        $opt = array();
@@ -2285,11 +2292,37 @@ function ' . $evalData . '(value) {
                                $sOnChange = 'setFormValueFromBrowseWin(\'' . $PA['itemFormElName'] . '\',this.options[this.selectedIndex].value, this.options[this.selectedIndex].text, this.options[this.selectedIndex].title); ';
                        }
                        $sOnChange .= implode('', $PA['fieldChangeFunc']);
+                       $multiSelectId = uniqid('tceforms-multiselect-');
                        $itemsToSelect = '
-                               <select id="' . uniqid('tceforms-multiselect-') . '" name="' . $PA['itemFormElName'] . '_sel"' . $this->insertDefStyle('select', 'tceforms-multiselect tceforms-itemstoselect') . ($size ? ' size="' . $size . '"' : '') . ' onchange="' . htmlspecialchars($sOnChange) . '"' . $PA['onFocus'] . $selector_itemListStyle . '>
+                               <select id="' . $multiSelectId . '" name="' . $PA['itemFormElName'] . '_sel"' . $this->insertDefStyle('select', 'tceforms-multiselect tceforms-itemstoselect') . ($size ? ' size="' . $size . '"' : '') . ' onchange="' . htmlspecialchars($sOnChange) . '"' . $PA['onFocus'] . $selector_itemListStyle . '>
                                        ' . implode('
                                        ', $opt) . '
                                </select>';
+
+                       if ($config['enableMultiSelectFilterTextfield'] || $config['multiSelectFilterItems']) {
+                               $this->multiSelectFilterCount++;
+                               $jsSelectBoxFilterName = str_replace(' ', '', ucwords(str_replace('-', ' ', GeneralUtility::strtolower($multiSelectId))));
+                               $this->additionalJS_post[] = '
+                                       var '. $jsSelectBoxFilterName . ' = new TCEForms.SelectBoxFilter("' . $multiSelectId . '");
+                               ';
+                       }
+
+                       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;" />';
+                       }
+
+                       if (isset($config['multiSelectFilterItems']) && is_array($config['multiSelectFilterItems']) && count($config['multiSelectFilterItems']) > 1) {
+                               $filterDropDownOptions = array();
+                               foreach($config['multiSelectFilterItems'] as $optionElement) {
+                                       $filterDropDownOptions[] = '<option value="' . htmlspecialchars($this->sL($optionElement[0])) . '">' . htmlspecialchars((isset($optionElement[1]) && $optionElement[1] != '') ? $this->sL($optionElement[1]) : $this->sL($optionElement[0])) . '</option>';
+                               }
+                               $filterSelectbox = '
+                                       <select id="' . $multiSelectId . '_filterdropdown">
+                                               ' . implode('
+                                               ', $filterDropDownOptions) . '
+                                       </select>';
+                       }
                }
                // Pass to "dbFileIcons" function:
                $params = array(
@@ -2301,7 +2334,7 @@ function ' . $evalData . '(value) {
                        'info' => '',
                        'headers' => array(
                                'selector' => $this->getLL('l_selected') . ':<br />',
-                               'items' => $this->getLL('l_items') . ':<br />'
+                               'items' => $this->getLL('l_items') . ': ' . $filterSelectbox . $filterTextfield . '<br />'
                        ),
                        'noBrowser' => 1,
                        'thumbnails' => $itemsToSelect,
@@ -5434,12 +5467,17 @@ function ' . $evalData . '(value) {
                                ';
                                // 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');
+                               }
                        }
                        // Toggle icons:
                        $toggleIcon_open = IconUtility::getSpriteIcon('actions-move-down', array('title' => 'Open'));
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_selectboxfilter.js b/typo3/sysext/backend/Resources/Public/JavaScript/jsfunc.tceforms_selectboxfilter.js
new file mode 100644 (file)
index 0000000..064c7f4
--- /dev/null
@@ -0,0 +1,118 @@
+/***************************************************************
+ *  JS selectbox filter for TCEforms
+ *
+ *  Copyright notice
+ *
+ *  (c) 2013 Marc Bastian Heinrichs <mbh@mbh-software.de>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * 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);
+                       }
+               }
+       }
+});
+