[BUGFIX] Migrate "Revert selection" of SelectCheckboxElement 28/60728/4
authorAndreas Fernandez <a.fernandez@scripting-base.de>
Fri, 10 May 2019 08:38:07 +0000 (10:38 +0200)
committerAndreas Fernandez <a.fernandez@scripting-base.de>
Fri, 10 May 2019 14:47:12 +0000 (16:47 +0200)
With #87324 parts of the FormEngine have been split into smaller,
maintainable parts. However, `SelectCheckboxElement` brings it's own
"Revert selection" implementation that has nothing in common with the
"Reset selection" field control used for select boxes.

The code is now rewritten to handle the revert on its own. Additionally,
another inline `onclick` handler was removed.

Resolves: #88314
Related: #87324
Releases: master
Change-Id: Ifca1b67a960a8caab8145f2a7d5c8301918819fa
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/60728
Tested-by: Frank Naegler <frank.naegler@typo3.org>
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: Frank Naegler <frank.naegler@typo3.org>
Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Build/Sources/TypeScript/backend/Resources/Public/TypeScript/FormEngine/Element/SelectCheckBoxElement.ts
typo3/sysext/backend/Classes/Form/Element/SelectCheckBoxElement.php
typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SelectCheckBoxElement.js

index 82c617b..8e51d8f 100644 (file)
@@ -17,11 +17,13 @@ import FormEngine = require('TYPO3/CMS/Backend/FormEngine');
 enum Identifier {
   toggleAll = '.t3js-toggle-checkboxes',
   singleItem = '.t3js-checkbox',
+  revertSelection = '.t3js-revert-selection',
 }
 
 class SelectCheckBoxElement {
   private checkBoxId: string = '';
   private $table: JQuery = null;
+  private checkedBoxes: JQuery = null;
 
   /**
    * Determines whether all available checkboxes are checked
@@ -40,6 +42,7 @@ class SelectCheckBoxElement {
     this.checkBoxId = checkBoxId;
     $((): void => {
       this.$table = $('#' + checkBoxId).closest('table');
+      this.checkedBoxes = this.$table.find(Identifier.singleItem + ':checked');
 
       this.enableTriggerCheckBox();
       this.registerEventHandler();
@@ -50,7 +53,7 @@ class SelectCheckBoxElement {
    * Registers the events for clicking the "Toggle all" and the single item checkboxes
    */
   private registerEventHandler(): void {
-    $(this.$table).on('change', Identifier.toggleAll, (e: JQueryEventObject): void => {
+    this.$table.on('change', Identifier.toggleAll, (e: JQueryEventObject): void => {
       const $me = $(e.currentTarget);
       const $checkBoxes = this.$table.find(Identifier.singleItem);
       const checkIt = !SelectCheckBoxElement.allCheckBoxesAreChecked($checkBoxes);
@@ -59,13 +62,22 @@ class SelectCheckBoxElement {
       $me.prop('checked', checkIt);
       FormEngine.Validation.markFieldAsChanged($me);
     }).on('change', Identifier.singleItem, (): void => {
-      const $checkBoxes = this.$table.find(Identifier.singleItem);
-      const checkIt = SelectCheckBoxElement.allCheckBoxesAreChecked($checkBoxes);
-
-      this.$table.find(Identifier.toggleAll).prop('checked', checkIt);
+      this.setToggleAllState();
+    }).on('click', Identifier.revertSelection, (): void => {
+      this.$table.find(Identifier.singleItem).each((_: number, checkbox: HTMLInputElement): void => {
+        checkbox.checked = this.checkedBoxes.index(checkbox) > -1;
+      });
+      this.setToggleAllState();
     });
   }
 
+  private setToggleAllState(): void {
+    const $checkBoxes = this.$table.find(Identifier.singleItem);
+    const checkIt = SelectCheckBoxElement.allCheckBoxesAreChecked($checkBoxes);
+
+    this.$table.find(Identifier.toggleAll).prop('checked', checkIt);
+  }
+
   /**
    * Enables the "Toggle all" checkbox on document load if all child checkboxes are checked
    */
index 81253de..6309116 100644 (file)
@@ -166,10 +166,11 @@ class SelectCheckBoxElement extends AbstractFormElement
             // Building the checkboxes
             foreach ($groups as $groupKey => $group) {
                 $groupId = htmlspecialchars($parameterArray['itemFormElID']) . '-group-' . $groupKey;
-                $html[] = '<div class="panel panel-default">';
+                $groupIdCollapsible = $groupId . '-collapse';
+                $html[] = '<div id="' . $groupId . '" class="panel panel-default">';
                 if (is_array($group['header'])) {
                     $html[] = '<div class="panel-heading">';
-                    $html[] = '<a data-toggle="collapse" href="#' . $groupId . '" aria-expanded="false" aria-controls="' . $groupId . '">';
+                    $html[] = '<a data-toggle="collapse" href="#' . $groupIdCollapsible . '" aria-expanded="false" aria-controls="' . $groupIdCollapsible . '">';
                     $html[] = $group['header']['icon'];
                     $html[] = htmlspecialchars($group['header']['title']);
                     $html[] = '</a>';
@@ -177,7 +178,6 @@ class SelectCheckBoxElement extends AbstractFormElement
                 }
                 if (is_array($group['items']) && !empty($group['items'])) {
                     $tableRows = [];
-                    $resetGroup = [];
 
                     // Render rows
                     foreach ($group['items'] as $item) {
@@ -199,24 +199,22 @@ class SelectCheckBoxElement extends AbstractFormElement
                         $tableRows[] =    '</td>';
                         $tableRows[] =    '<td class="text-right">' . $item['help'] . '</td>';
                         $tableRows[] = '</tr>';
-                        $resetGroup[] = 'document.editform[' . GeneralUtility::quoteJSvalue($item['name']) . '].checked=' . $item['checked'] . ';';
                     }
 
                     // Build reset group button
                     $resetGroupBtn = '';
-                    if (!empty($resetGroup)) {
-                        $resetGroup[] = 'TYPO3.FormEngine.updateCheckboxState(this);';
+                    if (!empty($group['items'])) {
                         $title = htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.revertSelection'));
-                        $resetGroupBtn = '<a href="#" '
-                            . 'class="btn btn-default btn-sm" '
-                            . 'onclick="' . implode('', $resetGroup) . ' return false;" '
-                            . 'title="' . $title . '">'
+                        $resetGroupBtn = '<button type="button" '
+                            . 'class="btn btn-default btn-sm t3js-revert-selection" '
+                            . 'title="' . $title . '"'
+                            . '>'
                             . $this->iconFactory->getIcon('actions-edit-undo', Icon::SIZE_SMALL)->render() . ' '
-                            . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.revertSelection') . '</a>';
+                            . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.revertSelection') . '</button>';
                     }
 
                     if (is_array($group['header'])) {
-                        $html[] = '<div id="' . $groupId . '" class="panel-collapse collapse" role="tabpanel">';
+                        $html[] = '<div id="' . $groupIdCollapsible . '" class="panel-collapse collapse" role="tabpanel">';
                     }
                     $checkboxId = uniqid($groupId);
                     $title = htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.toggleall'));
index f0a3da9..a2599ae 100644 (file)
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-define(["require","exports","jquery","TYPO3/CMS/Backend/FormEngine"],function(e,t,n,c){"use strict";var l,r;return(r=l||(l={})).toggleAll=".t3js-toggle-checkboxes",r.singleItem=".t3js-checkbox",function(){function e(e){var t=this;this.checkBoxId="",this.$table=null,this.checkBoxId=e,n(function(){t.$table=n("#"+e).closest("table"),t.enableTriggerCheckBox(),t.registerEventHandler()})}return e.allCheckBoxesAreChecked=function(e){return e.length===e.filter(":checked").length},e.prototype.registerEventHandler=function(){var t=this;n(this.$table).on("change",l.toggleAll,function(r){var i=n(r.currentTarget),o=t.$table.find(l.singleItem),h=!e.allCheckBoxesAreChecked(o);o.prop("checked",h),i.prop("checked",h),c.Validation.markFieldAsChanged(i)}).on("change",l.singleItem,function(){var n=t.$table.find(l.singleItem),c=e.allCheckBoxesAreChecked(n);t.$table.find(l.toggleAll).prop("checked",c)})},e.prototype.enableTriggerCheckBox=function(){var t=this.$table.find(l.singleItem),c=e.allCheckBoxesAreChecked(t);n("#"+this.checkBoxId).prop("checked",c)},e}()});
\ No newline at end of file
+define(["require","exports","jquery","TYPO3/CMS/Backend/FormEngine"],function(e,t,n,c){"use strict";var l,i;return(i=l||(l={})).toggleAll=".t3js-toggle-checkboxes",i.singleItem=".t3js-checkbox",i.revertSelection=".t3js-revert-selection",function(){function e(e){var t=this;this.checkBoxId="",this.$table=null,this.checkedBoxes=null,this.checkBoxId=e,n(function(){t.$table=n("#"+e).closest("table"),t.checkedBoxes=t.$table.find(l.singleItem+":checked"),t.enableTriggerCheckBox(),t.registerEventHandler()})}return e.allCheckBoxesAreChecked=function(e){return e.length===e.filter(":checked").length},e.prototype.registerEventHandler=function(){var t=this;this.$table.on("change",l.toggleAll,function(i){var o=n(i.currentTarget),r=t.$table.find(l.singleItem),h=!e.allCheckBoxesAreChecked(r);r.prop("checked",h),o.prop("checked",h),c.Validation.markFieldAsChanged(o)}).on("change",l.singleItem,function(){t.setToggleAllState()}).on("click",l.revertSelection,function(){t.$table.find(l.singleItem).each(function(e,n){n.checked=t.checkedBoxes.index(n)>-1}),t.setToggleAllState()})},e.prototype.setToggleAllState=function(){var t=this.$table.find(l.singleItem),n=e.allCheckBoxesAreChecked(t);this.$table.find(l.toggleAll).prop("checked",n)},e.prototype.enableTriggerCheckBox=function(){var t=this.$table.find(l.singleItem),c=e.allCheckBoxesAreChecked(t);n("#"+this.checkBoxId).prop("checked",c)},e}()});
\ No newline at end of file