[FEATURE] Introduce AJAX functionality for list module 54/33654/17
authorBenjamin Mack <benni@typo3.org>
Mon, 8 Dec 2014 20:03:40 +0000 (21:03 +0100)
committerHelmut Hummel <helmut.hummel@typo3.org>
Tue, 9 Dec 2014 11:19:36 +0000 (12:19 +0100)
This patch add a new JavaScript file to optimize the list module
with AJAX calls for hide and unhide of records.

More functions like delete and the logic for the page module
will follow in a separate patch.

Resolves: #62576
Releases: master
Change-Id: Id676cd48306c65c30899ec36a31f123d9b5bb16e
Reviewed-on: http://review.typo3.org/33654
Reviewed-by: Benjamin Mack <benni@typo3.org>
Tested-by: Benjamin Mack <benni@typo3.org>
Reviewed-by: Helmut Hummel <helmut.hummel@typo3.org>
Tested-by: Helmut Hummel <helmut.hummel@typo3.org>
typo3/sysext/backend/Classes/Controller/SimpleDataHandlerController.php
typo3/sysext/backend/Classes/RecordList/AbstractRecordList.php
typo3/sysext/backend/Resources/Public/JavaScript/AjaxDataHandler.js [new file with mode: 0644]
typo3/sysext/core/Configuration/DefaultConfiguration.php
typo3/sysext/recordlist/Classes/RecordList.php
typo3/sysext/recordlist/Classes/RecordList/DatabaseRecordList.php

index 2e49ca0..03c7769 100644 (file)
@@ -246,4 +246,42 @@ class SimpleDataHandlerController {
                }
        }
 
+       /**
+        * Processes all AJAX calls and returns a JSON formatted string
+        *
+        * @param array $parameters
+        * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxRequestHandler
+        */
+       public function processAjaxRequest($parameters, \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxRequestHandler) {
+               // do the regular / main logic
+               $this->initClipboard();
+               $this->main();
+
+               $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
+
+               $content = array(
+                       'redirect' => $this->redirect,
+                       'messages' => array(),
+                       'hasErrors' => FALSE
+               );
+
+               // Prints errors (= write them to the message queue)
+               if ($this->prErr) {
+                       $content['hasErrors'] = TRUE;
+                       $this->tce->printLogErrorMessages($this->redirect);
+               }
+
+               $messages = $flashMessageService->getMessageQueueByIdentifier()->getAllMessagesAndFlush();
+               if (!empty($messages)) {
+                       foreach ($messages as $message) {
+                               $content['messages'][] = array(
+                                       'title'    => $message->getTitle(),
+                                       'message'  => $message->getMessage(),
+                                       'severity' => $message->getSeverity()
+                               );
+                       }
+               }
+               $ajaxRequestHandler->setContentFormat('json');
+               $ajaxRequestHandler->setContent($content);
+       }
 }
index eb63a19..3070854 100644 (file)
@@ -209,7 +209,7 @@ abstract class AbstractRecordList {
                // Start up:
                $out = '
                <!-- Element, begin: -->
-               <tr ' . $rowParams . '>';
+               <tr ' . $rowParams . ' data-uid="' . (int)$data['uid'] . '">';
                // Show icon and lines
                if ($this->showIcon) {
                        $out .= '
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/AjaxDataHandler.js b/typo3/sysext/backend/Resources/Public/JavaScript/AjaxDataHandler.js
new file mode 100644 (file)
index 0000000..dcd61ae
--- /dev/null
@@ -0,0 +1,108 @@
+/**
+ * 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!
+ */
+
+/**
+ * AjaxDataHandler - Javascript functions to work with AJAX and interacting with tce_db.php
+ */
+define('TYPO3/CMS/Backend/AjaxDataHandler', ['jquery', 'TYPO3/CMS/Backend/FlashMessages'], function ($) {
+       var AjaxDataHandler = {};
+
+       AjaxDataHandler.initialize = function() {
+
+               // click events for all action icons to hide/unhide
+               $(document).on('click', '.t3js-record-hide', function(evt) {
+                       evt.preventDefault();
+                       var $anchorElement = $(this);
+                       var $iconElement   = $anchorElement.find('span');
+                       var $rowElement    = $anchorElement.closest('tr[data-uid]');
+                       var table  = $anchorElement.closest('table[data-table]').data('table');
+                       var hasVisibleState  = $anchorElement.data('state') === 'visible';
+                       var params = $anchorElement.data('params');
+
+                       var removeClass = hasVisibleState ? 'fa-toggle-on' : 'fa-toggle-off';
+                       var addClass    = hasVisibleState ? 'fa-toggle-off' : 'fa-toggle-on';
+                       var nextState   = hasVisibleState ? 'hidden' : 'visible';
+                       var nextParams  = hasVisibleState ? params.replace('=1', '=0') : params.replace('=0', '=1');
+
+                       // add a spinner
+                       $iconElement.removeClass(removeClass);
+                       AjaxDataHandler._showSpinnerIcon($iconElement);
+
+                       // make the AJAX call to toggle the visibility
+                       AjaxDataHandler._call(params).done(function(result) {
+                               AjaxDataHandler._hideSpinnerIcon($iconElement);
+                               // print messages on errors
+                               if (result.hasErrors) {
+                                       $.each(result.messages, function(position, message) {
+                                               top.TYPO3.Flashmessage.display(message.severity, message.title, message.message);
+                                       });
+                                       // revert to the old class
+                                       $iconElement.addClass(removeClass);
+                               } else {
+                                       $anchorElement.data('state', nextState).data('params', nextParams);
+                                       $iconElement.removeClass(removeClass).addClass(addClass);
+                                       if (nextState === 'hidden') {
+                                               // add overlay icon
+                                               $rowElement.find('td.col-icon span.t3-icon').append('<span class="t3-icon t3-icon-status t3-icon-status-overlay t3-icon-overlay-hidden t3-icon-overlay">&nbsp;</span>');
+                                       } else {
+                                               // remove overlay icon
+                                               $rowElement.find('td.col-icon span.t3-icon span.t3-icon').remove();
+                                       }
+                                       $rowElement.fadeTo('fast', 0.4, function() {
+                                               $rowElement.fadeTo('fast', 1);
+                                       });
+
+                                       if (table === 'pages' && top.TYPO3 && top.TYPO3.Backend && top.TYPO3.Backend.NavigationContainer && top.TYPO3.Backend.NavigationContainer.PageTree) {
+                                               top.TYPO3.Backend.NavigationContainer.PageTree.refreshTree();
+                                       }
+                               }
+
+                       });
+               });
+       };
+
+       /**
+        * AJAX call to tce_db.php
+        * returns a jQuery Promise to work with
+        * @private
+        */
+       AjaxDataHandler._call = function(params) {
+               return $.getJSON(TYPO3.settings.ajaxUrls['DataHandler::process'], params);
+       };
+
+       /**
+        * Replace the given icon with a spinner icon
+        * @private
+        */
+       AjaxDataHandler._showSpinnerIcon = function($iconElement) {
+               $iconElement.addClass('fa-spin fa-circle-o-notch');
+       };
+
+       /**
+        * Removes the spinner icon classes
+        * @private
+        */
+       AjaxDataHandler._hideSpinnerIcon = function($iconElement) {
+               $iconElement.removeClass('fa-spin fa-circle-o-notch');
+       };
+
+       /**
+        * initialize and return the object
+        */
+       return function() {
+               AjaxDataHandler.initialize();
+
+               // return the object in the global space
+               return AjaxDataHandler;
+       }();
+});
index 3957818..513e8d0 100644 (file)
@@ -701,6 +701,10 @@ return array(
                                'callbackMethod' => \TYPO3\CMS\Backend\Controller\ClickMenuController::class . '->printContentForAjaxRequest',
                                'csrfTokenCheck' => TRUE
                        ),
+                       'DataHandler::process' => array(
+                               'callbackMethod' => \TYPO3\CMS\Backend\Controller\SimpleDataHandlerController::class . '->processAjaxRequest',
+                               'csrfTokenCheck' => TRUE
+                       )
                ),
                'toolbarItems' => array(), // Array: Registered toolbar items classes
                'HTTP' => array(
index e75b8f2..711c2dc 100644 (file)
@@ -237,6 +237,7 @@ class RecordList {
                $this->doc = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Template\DocumentTemplate::class);
                $this->doc->backPath = $GLOBALS['BACK_PATH'];
                $this->doc->setModuleTemplate('EXT:recordlist/Resources/Private/Templates/db_list.html');
+               $this->doc->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/AjaxDataHandler');
                // Loading current page record and checking access:
                $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
                $access = is_array($this->pageinfo) ? 1 : 0;
index 84fcb94..db74225 100644 (file)
@@ -631,7 +631,7 @@ class DatabaseRecordList extends AbstractDatabaseRecordList {
                                        ' . $tableHeader . '
                                        </div>
                                        <div class="table-fit">
-                                               <table class="table table-hover' . ($listOnlyInSingleTableMode ? ' typo3-dblist-overview' : '') . '">
+                                               <table data-table="' . htmlspecialchars($table) . '" class="table table-hover' . ($listOnlyInSingleTableMode ? ' typo3-dblist-overview' : '') . '">
                                                        ' . $out . '
                                                </table>
                                        </div>
@@ -792,6 +792,7 @@ class DatabaseRecordList extends AbstractDatabaseRecordList {
                        $this->addElement_tdCssClass['_LOCALIZATION_'] = 'col-localizationa';
                        $this->addElement_tdCssClass['_LOCALIZATION_b'] = 'col-localizationb';
                        // Create element in table cells:
+                       $theData['uid'] = $row['uid'];
                        $iOut .= $this->addelement(1, $theIcon, $theData, $row_bgColor);
                        // Finally, return table row element:
                        return $iOut;
@@ -1274,16 +1275,16 @@ class DatabaseRecordList extends AbstractDatabaseRecordList {
                                                || $GLOBALS['BE_USER']->check('non_exclude_fields', $table . ':' . $hiddenField))
                                ) {
                                        if ($row[$hiddenField]) {
-                                               $params = '&data[' . $table . '][' . $rowUid . '][' . $hiddenField . ']=0';
-                                               $cells['hide'] = '<a class="btn" href="#" onclick="'
-                                                       . htmlspecialchars('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');')
-                                                       . '" title="' . $GLOBALS['LANG']->getLL(('unHide' . ($table == 'pages' ? 'Page' : '')), TRUE) . '">'
+                                               $params = 'data[' . $table . '][' . $rowUid . '][' . $hiddenField . ']=0';
+                                               $cells['hide'] = '<a class="btn t3js-record-hide" data-state="hidden" href="#"'
+                                                       . ' data-params="' . htmlspecialchars($params) . '"'
+                                                       . ' title="' . $GLOBALS['LANG']->getLL(('unHide' . ($table == 'pages' ? 'Page' : '')), TRUE) . '">'
                                                        . IconUtility::getSpriteIcon('actions-edit-unhide') . '</a>';
                                        } else {
-                                               $params = '&data[' . $table . '][' . $rowUid . '][' . $hiddenField . ']=1';
-                                               $cells['hide'] = '<a class="btn" href="#" onclick="'
-                                                       . htmlspecialchars('return jumpToUrl(\'' . $GLOBALS['SOBE']->doc->issueCommand($params, -1) . '\');')
-                                                       . '" title="' . $GLOBALS['LANG']->getLL(('hide' . ($table == 'pages' ? 'Page' : '')), TRUE) . '">'
+                                               $params = 'data[' . $table . '][' . $rowUid . '][' . $hiddenField . ']=1';
+                                               $cells['hide'] = '<a class="btn t3js-record-hide" data-state="visible" href="#"'
+                                                       . ' data-params="' . htmlspecialchars($params) . '"'
+                                                       . ' title="' . $GLOBALS['LANG']->getLL(('hide' . ($table == 'pages' ? 'Page' : '')), TRUE) . '">'
                                                        . IconUtility::getSpriteIcon('actions-edit-hide') . '</a>';
                                        }
                                }