[TASK] Move clipboard inline JavaScript into separate modules 41/62041/2
authorAndreas Fernandez <a.fernandez@scripting-base.de>
Tue, 22 Oct 2019 08:27:20 +0000 (10:27 +0200)
committerDaniel Goerz <daniel.goerz@posteo.de>
Sat, 9 Nov 2019 18:57:28 +0000 (19:57 +0100)
This patch moves the inline JavaScript for clipboard handling into a
separate module that is re-used in record list and in file list.

Additionally, the function `editList` only used in record list context
has been moved into the according module.

Resolves: #89476
Releases: master
Change-Id: I43c972aadd8cd097850139813a01c3560a9b202c
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/62041
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Susanne Moog <look@susi.dev>
Tested-by: Daniel Goerz <daniel.goerz@posteo.de>
Reviewed-by: Susanne Moog <look@susi.dev>
Reviewed-by: Daniel Goerz <daniel.goerz@posteo.de>
Build/Sources/TypeScript/backend/Resources/Public/TypeScript/ClipboardComponent.ts [new file with mode: 0644]
Build/Sources/TypeScript/recordlist/Resources/Public/TypeScript/Recordlist.ts
typo3/sysext/backend/Classes/View/PageLayoutView.php
typo3/sysext/backend/Resources/Public/JavaScript/ClipboardComponent.js [new file with mode: 0644]
typo3/sysext/filelist/Classes/Controller/FileListController.php
typo3/sysext/filelist/Classes/FileList.php
typo3/sysext/recordlist/Classes/Controller/RecordListController.php
typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php
typo3/sysext/recordlist/Resources/Public/JavaScript/Recordlist.js

diff --git a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/ClipboardComponent.ts b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/ClipboardComponent.ts
new file mode 100644 (file)
index 0000000..80502f0
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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 ClipboardComponent {
+  private static setCheckboxValue(checkboxName: string, check: boolean): void {
+    const fullName = 'CBC[' + checkboxName + ']';
+    const checkboxElement: HTMLInputElement = document.querySelector('form[name="dblistForm"] [name="' + fullName + '"]');
+    if (checkboxElement !== null) {
+      checkboxElement.checked = check;
+    }
+  }
+
+  constructor() {
+    this.registerCheckboxTogglers();
+  }
+
+  private registerCheckboxTogglers(): void {
+    const selector = 'a.t3js-toggle-all-checkboxes';
+    document.addEventListener('click', (e: Event): void => {
+      let target = <HTMLElement>e.target;
+      if (!target.matches(selector)) {
+        let closest: HTMLElement = target.closest(selector);
+        if (closest !== null) {
+          target = closest;
+        } else {
+          return;
+        }
+      }
+
+      e.preventDefault();
+
+      let flagAll: boolean;
+      if (target.getAttribute('rel') === '') {
+        target.setAttribute('rel', 'allChecked');
+        flagAll = true;
+      } else {
+        target.setAttribute('rel', '');
+        flagAll = false;
+      }
+
+      const listOfCheckboxNames: Array<string> = target.dataset.checkboxesNames.split(',');
+      for (let checkboxName of listOfCheckboxNames) {
+        ClipboardComponent.setCheckboxValue(checkboxName, flagAll);
+      }
+    });
+  }
+}
+
+export = new ClipboardComponent();
index cdb7fae..8b8feb5 100644 (file)
@@ -17,7 +17,6 @@ import Icons = require('TYPO3/CMS/Backend/Icons');
 
 declare global {
   const T3_THIS_LOCATION: string;
-  const editList: Function;
 }
 
 interface IconIdentifier {
@@ -131,7 +130,7 @@ class Recordlist {
 
       $.each(pipes, (pipeIndex: string, pipe: string): void => {
         if (pipe === 'editList') {
-          value = editList(tableName, value);
+          value = this.editList(tableName, value);
         }
       });
 
@@ -141,11 +140,37 @@ class Recordlist {
     window.location.href = uri;
   }
 
+  private editList(table: string, idList: string): string {
+    const list: Array<string> = [];
+
+    let pointer = 0;
+    let pos = idList.indexOf(',');
+    while (pos !== -1) {
+      if (this.getCheckboxState(table + '|' + idList.substr(pointer, pos - pointer))) {
+        list.push(idList.substr(pointer, pos - pointer));
+      }
+      pointer = pos + 1;
+      pos = idList.indexOf(',', pointer);
+    }
+
+    if (this.getCheckboxState(table + '|' + idList.substr(pointer))) {
+      list.push(idList.substr(pointer));
+    }
+
+    return list.length > 0 ? list.join(',') : idList;
+  }
+
   private disableButton = (event: JQueryEventObject): void => {
     const $me = $(event.currentTarget);
 
     $me.prop('disable', true).addClass('disabled');
   }
+
+  private getCheckboxState(CBname: string): boolean {
+    const fullName = 'CBC[' + CBname + ']';
+    const checkbox: HTMLInputElement = document.querySelector('form[name="dblistForm"] [name="' + fullName + '"]');
+    return checkbox.checked;
+  }
 }
 
 export = new Recordlist();
index 965b8f6..bd50a9c 100644 (file)
@@ -4011,45 +4011,6 @@ class PageLayoutView implements LoggerAwareInterface
     }
 
     /**
-     * Returning JavaScript for ClipBoard functionality.
-     *
-     * @return string
-     */
-    public function CBfunctions()
-    {
-        return '
-               // checkOffCB()
-       function checkOffCB(listOfCBnames, link) {      //
-               var checkBoxes, flag, i;
-               var checkBoxes = listOfCBnames.split(",");
-               if (link.rel === "") {
-                       link.rel = "allChecked";
-                       flag = true;
-               } else {
-                       link.rel = "";
-                       flag = false;
-               }
-               for (i = 0; i < checkBoxes.length; i++) {
-                       setcbValue(checkBoxes[i], flag);
-               }
-       }
-               // cbValue()
-       function cbValue(CBname) {      //
-               var CBfullName = "CBC["+CBname+"]";
-               return (document.dblistForm[CBfullName] && document.dblistForm[CBfullName].checked ? 1 : 0);
-       }
-               // setcbValue()
-       function setcbValue(CBname,flag) {      //
-               CBfullName = "CBC["+CBname+"]";
-               if(document.dblistForm[CBfullName]) {
-                       document.dblistForm[CBfullName].checked = flag ? "on" : 0;
-               }
-       }
-
-               ';
-    }
-
-    /**
      * Initializes page languages
      */
     public function initializeLanguages()
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/ClipboardComponent.js b/typo3/sysext/backend/Resources/Public/JavaScript/ClipboardComponent.js
new file mode 100644 (file)
index 0000000..268d8f3
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * 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!
+ */
+define(["require","exports"],function(e,t){"use strict";class r{static setCheckboxValue(e,t){const r="CBC["+e+"]",s=document.querySelector('form[name="dblistForm"] [name="'+r+'"]');null!==s&&(s.checked=t)}constructor(){this.registerCheckboxTogglers()}registerCheckboxTogglers(){const e="a.t3js-toggle-all-checkboxes";document.addEventListener("click",t=>{let s,c=t.target;if(!c.matches(e)){let t=c.closest(e);if(null===t)return;c=t}t.preventDefault(),""===c.getAttribute("rel")?(c.setAttribute("rel","allChecked"),s=!0):(c.setAttribute("rel",""),s=!1);const l=c.dataset.checkboxesNames.split(",");for(let e of l)r.setCheckboxValue(e,s)})}}return new r});
\ No newline at end of file
index 8cf6baf..32c8b90 100644 (file)
@@ -389,9 +389,10 @@ class FileListController extends ActionController implements LoggerAwareInterfac
             // Set top JavaScript:
             $this->view->getModuleTemplate()->addJavaScriptCode(
                 'FileListIndex',
-                'if (top.fsMod) top.fsMod.recentIds["file"] = "' . rawurlencode($this->id) . '";' . $this->filelist->CBfunctions() . '
+                'if (top.fsMod) top.fsMod.recentIds["file"] = "' . rawurlencode($this->id) . '";
                 '
             );
+            $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ClipboardComponent');
             $pageRenderer->loadRequireJsModule('TYPO3/CMS/Filelist/FileDelete');
             $pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf', 'buttons');
 
index 68e3666..8d5f80c 100644 (file)
@@ -506,8 +506,7 @@ class FileList
                         if ($this->folderObject->checkActionPermission('delete')) {
                             $cells[] = $this->linkClipboardHeaderIcon('<span title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_deleteMarked')) . '">' . $this->iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL)->render(), $table, 'delete', $this->getLanguageService()->getLL('clip_deleteMarkedWarning'));
                         }
-                        $onClick = 'checkOffCB(' . GeneralUtility::quoteJSvalue(implode(',', $this->CBnames)) . ', this); return false;';
-                        $cells[] = '<a class="btn btn-default" rel="" href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_markRecords')) . '">' . $this->iconFactory->getIcon('actions-document-select', Icon::SIZE_SMALL)->render() . '</a>';
+                        $cells[] = '<a class="btn btn-default t3js-toggle-all-checkboxes" data-checkboxes-names="' . htmlspecialchars(implode(',', $this->CBnames)) . '" rel="" href="#" title="' . htmlspecialchars($this->getLanguageService()->getLL('clip_markRecords')) . '">' . $this->iconFactory->getIcon('actions-document-select', Icon::SIZE_SMALL)->render() . '</a>';
                     }
                     $theData[$v] = implode('', $cells);
                 } elseif ($v === '_REF_') {
@@ -709,45 +708,6 @@ class FileList
     }
 
     /**
-     * Returning JavaScript for ClipBoard functionality.
-     *
-     * @return string
-     */
-    public function CBfunctions()
-    {
-        return '
-               // checkOffCB()
-       function checkOffCB(listOfCBnames, link) {      //
-               var checkBoxes, flag, i;
-               var checkBoxes = listOfCBnames.split(",");
-               if (link.rel === "") {
-                       link.rel = "allChecked";
-                       flag = true;
-               } else {
-                       link.rel = "";
-                       flag = false;
-               }
-               for (i = 0; i < checkBoxes.length; i++) {
-                       setcbValue(checkBoxes[i], flag);
-               }
-       }
-               // cbValue()
-       function cbValue(CBname) {      //
-               var CBfullName = "CBC["+CBname+"]";
-               return (document.dblistForm[CBfullName] && document.dblistForm[CBfullName].checked ? 1 : 0);
-       }
-               // setcbValue()
-       function setcbValue(CBname,flag) {      //
-               CBfullName = "CBC["+CBname+"]";
-               if(document.dblistForm[CBfullName]) {
-                       document.dblistForm[CBfullName].checked = flag ? "on" : 0;
-               }
-       }
-
-               ';
-    }
-
-    /**
      * Initializes page languages and icons
      */
     public function initializeLanguages()
index 47c1bb2..4098aa7 100644 (file)
@@ -366,7 +366,9 @@ class RecordListController
             // Render the list of tables:
             $dblist->generateList();
             $listUrl = $dblist->listURL();
+
             // Add JavaScript functions to the page:
+            $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ClipboardComponent');
 
             $this->moduleTemplate->addJavaScriptCode(
                 'RecordListInlineJS',
@@ -392,29 +394,9 @@ class RecordListController
                                        }
                                }
                                ' . $this->moduleTemplate->redirectUrls($listUrl) . '
-                               ' . $dblist->CBfunctions() . '
                                function editRecords(table,idList,addParams,CBflag) {
                                        window.location.href="' . (string)$uriBuilder->buildUriFromRoute('record_edit', ['returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')]) . '&edit["+table+"]["+idList+"]=edit"+addParams;
                                }
-                               function editList(table,idList) {
-                                       var list="";
-
-                                               // Checking how many is checked, how many is not
-                                       var pointer=0;
-                                       var pos = idList.indexOf(",");
-                                       while (pos!=-1) {
-                                               if (cbValue(table+"|"+idList.substr(pointer,pos-pointer))) {
-                                                       list+=idList.substr(pointer,pos-pointer)+",";
-                                               }
-                                               pointer=pos+1;
-                                               pos = idList.indexOf(",",pointer);
-                                       }
-                                       if (cbValue(table+"|"+idList.substr(pointer))) {
-                                               list+=idList.substr(pointer)+",";
-                                       }
-
-                                       return list ? list : idList;
-                               }
 
                                if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';
                        '
index a5ec12b..827feab 100644 (file)
@@ -1488,8 +1488,7 @@ class DatabaseRecordList
                             $lang->getLL('clip_deleteMarked')
                         );
                         // The "Select all" link:
-                        $onClick = htmlspecialchars('checkOffCB(' . GeneralUtility::quoteJSvalue(implode(',', $this->CBnames)) . ', this); return false;');
-                        $cells['markAll'] = '<a class="btn btn-default" rel="" href="#" onclick="' . $onClick . '" title="'
+                        $cells['markAll'] = '<a class="btn btn-default t3js-toggle-all-checkboxes" data-checkboxes-names="' . htmlspecialchars(implode(',', $this->CBnames)) . '" rel="" href="#" title="'
                             . htmlspecialchars($lang->getLL('clip_markRecords')) . '">'
                             . $this->iconFactory->getIcon('actions-document-select', Icon::SIZE_SMALL)->render() . '</a>';
                     } else {
@@ -3899,45 +3898,6 @@ class DatabaseRecordList
     }
 
     /**
-     * Returning JavaScript for ClipBoard functionality.
-     *
-     * @return string
-     */
-    public function CBfunctions()
-    {
-        return '
-               // checkOffCB()
-       function checkOffCB(listOfCBnames, link) {      //
-               var checkBoxes, flag, i;
-               var checkBoxes = listOfCBnames.split(",");
-               if (link.rel === "") {
-                       link.rel = "allChecked";
-                       flag = true;
-               } else {
-                       link.rel = "";
-                       flag = false;
-               }
-               for (i = 0; i < checkBoxes.length; i++) {
-                       setcbValue(checkBoxes[i], flag);
-               }
-       }
-               // cbValue()
-       function cbValue(CBname) {      //
-               var CBfullName = "CBC["+CBname+"]";
-               return (document.dblistForm[CBfullName] && document.dblistForm[CBfullName].checked ? 1 : 0);
-       }
-               // setcbValue()
-       function setcbValue(CBname,flag) {      //
-               CBfullName = "CBC["+CBname+"]";
-               if(document.dblistForm[CBfullName]) {
-                       document.dblistForm[CBfullName].checked = flag ? "on" : 0;
-               }
-       }
-
-               ';
-    }
-
-    /**
      * Initializes page languages and icons
      */
     public function initializeLanguages()
index 40e1e7d..ecae52a 100644 (file)
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-define(["require","exports","jquery","TYPO3/CMS/Backend/Storage/Persistent","TYPO3/CMS/Backend/Icons"],function(t,e,i,a,s){"use strict";return new class{constructor(){this.identifier={entity:".t3js-entity",toggle:".t3js-toggle-recordlist",localize:".t3js-action-localize",icons:{collapse:"actions-view-list-collapse",expand:"actions-view-list-expand",editMultiple:".t3js-record-edit-multiple"}},this.toggleClick=(t=>{t.preventDefault();const e=i(t.currentTarget),l=e.data("table"),n=i(e.data("target")),d="expanded"===n.data("state"),o=e.find(".collapseIcon"),c=d?this.identifier.icons.expand:this.identifier.icons.collapse;s.getIcon(c,s.sizes.small).done(t=>{o.html(t)});let r={};a.isset("moduleData.list")&&(r=a.get("moduleData.list"));const u={};u[l]=d?1:0,i.extend(!0,r,u),a.set("moduleData.list",r).done(()=>{n.data("state",d?"collapsed":"expanded")})}),this.onEditMultiple=(t=>{let e,a,s,l,n;t.preventDefault(),0!==(e=i(t.currentTarget).closest("[data-table]")).length&&(l=i(t.currentTarget).data("uri"),a=e.data("table"),s=e.find(this.identifier.entity+'[data-uid][data-table="'+a+'"]').map((t,e)=>i(e).data("uid")).toArray().join(","),n=l.match(/{[^}]+}/g),i.each(n,(t,e)=>{const n=e.substr(1,e.length-2).split(":");let d;switch(n.shift()){case"entityIdentifiers":d=s;break;case"T3_THIS_LOCATION":d=T3_THIS_LOCATION;break;default:return}i.each(n,(t,e)=>{"editList"===e&&(d=editList(a,d))}),l=l.replace(e,d)}),window.location.href=l)}),this.disableButton=(t=>{i(t.currentTarget).prop("disable",!0).addClass("disabled")}),i(document).on("click",this.identifier.toggle,this.toggleClick),i(document).on("click",this.identifier.icons.editMultiple,this.onEditMultiple),i(document).on("click",this.identifier.localize,this.disableButton)}}});
\ No newline at end of file
+define(["require","exports","jquery","TYPO3/CMS/Backend/Storage/Persistent","TYPO3/CMS/Backend/Icons"],function(t,e,i,s,a){"use strict";return new class{constructor(){this.identifier={entity:".t3js-entity",toggle:".t3js-toggle-recordlist",localize:".t3js-action-localize",icons:{collapse:"actions-view-list-collapse",expand:"actions-view-list-expand",editMultiple:".t3js-record-edit-multiple"}},this.toggleClick=(t=>{t.preventDefault();const e=i(t.currentTarget),n=e.data("table"),l=i(e.data("target")),d="expanded"===l.data("state"),o=e.find(".collapseIcon"),c=d?this.identifier.icons.expand:this.identifier.icons.collapse;a.getIcon(c,a.sizes.small).done(t=>{o.html(t)});let r={};s.isset("moduleData.list")&&(r=s.get("moduleData.list"));const u={};u[n]=d?1:0,i.extend(!0,r,u),s.set("moduleData.list",r).done(()=>{l.data("state",d?"collapsed":"expanded")})}),this.onEditMultiple=(t=>{let e,s,a,n,l;t.preventDefault(),0!==(e=i(t.currentTarget).closest("[data-table]")).length&&(n=i(t.currentTarget).data("uri"),s=e.data("table"),a=e.find(this.identifier.entity+'[data-uid][data-table="'+s+'"]').map((t,e)=>i(e).data("uid")).toArray().join(","),l=n.match(/{[^}]+}/g),i.each(l,(t,e)=>{const l=e.substr(1,e.length-2).split(":");let d;switch(l.shift()){case"entityIdentifiers":d=a;break;case"T3_THIS_LOCATION":d=T3_THIS_LOCATION;break;default:return}i.each(l,(t,e)=>{"editList"===e&&(d=this.editList(s,d))}),n=n.replace(e,d)}),window.location.href=n)}),this.disableButton=(t=>{i(t.currentTarget).prop("disable",!0).addClass("disabled")}),i(document).on("click",this.identifier.toggle,this.toggleClick),i(document).on("click",this.identifier.icons.editMultiple,this.onEditMultiple),i(document).on("click",this.identifier.localize,this.disableButton)}editList(t,e){const i=[];let s=0,a=e.indexOf(",");for(;-1!==a;)this.getCheckboxState(t+"|"+e.substr(s,a-s))&&i.push(e.substr(s,a-s)),s=a+1,a=e.indexOf(",",s);return this.getCheckboxState(t+"|"+e.substr(s))&&i.push(e.substr(s)),i.length>0?i.join(","):e}getCheckboxState(t){const e="CBC["+t+"]";return document.querySelector('form[name="dblistForm"] [name="'+e+'"]').checked}}});
\ No newline at end of file