Commit 51e5d1af authored by Benni Mack's avatar Benni Mack Committed by Frank Nägler
Browse files

[TASK] Move FormEngine SelectboxFilter to jQuery

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's avatarOliver Hader <oliver.hader@typo3.org>
Tested-by: Oliver Hader's avatarOliver Hader <oliver.hader@typo3.org>
Reviewed-by: default avatarFrank Nägler <typo3@naegler.net>
Tested-by: default avatarFrank Nägler <typo3@naegler.net>
parent 799d738b
......@@ -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,
......
......@@ -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) . '";
......
......@@ -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();
}();
});
/**
* 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);
}
}
}
});
......@@ -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;
......
......@@ -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;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment