[FEATURE] Backend paginate widget
authorJigal van Hemert <jigal@xs4all.nl>
Fri, 26 Oct 2012 19:00:05 +0000 (21:00 +0200)
committerHelmut Hummel <helmut.hummel@typo3.org>
Wed, 31 Oct 2012 21:04:02 +0000 (22:04 +0100)
Backend modules such as the List module have a paginator which is quite
different from the paginate widget which was backported from Flow.

Change-Id: I48fcffa78ef90939f09a93d65273d9535fb13f0b
Resolves: #42428
Releases: 6.0
Reviewed-on: http://review.typo3.org/15961
Reviewed-by: Helmut Hummel
Tested-by: Helmut Hummel
typo3/sysext/fluid/Classes/ViewHelpers/Be/Widget/Controller/PaginateController.php [new file with mode: 0644]
typo3/sysext/fluid/Classes/ViewHelpers/Be/Widget/PaginateViewHelper.php [new file with mode: 0644]
typo3/sysext/fluid/Resources/Private/Language/locallang.xlf
typo3/sysext/fluid/Resources/Private/Templates/ViewHelpers/Be/Widget/Paginate/Index.html [new file with mode: 0644]

diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/Be/Widget/Controller/PaginateController.php b/typo3/sysext/fluid/Classes/ViewHelpers/Be/Widget/Controller/PaginateController.php
new file mode 100644 (file)
index 0000000..1461cf1
--- /dev/null
@@ -0,0 +1,132 @@
+<?php
+namespace TYPO3\CMS\Fluid\ViewHelpers\Be\Widget\Controller;
+
+/*                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU Lesser General Public License, either version 3   *
+ *  of the License, or (at your option) any later version.                *
+ *                                                                        *
+ *                                                                        *
+ * This script is distributed in the hope that it will be useful, but     *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
+ * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser       *
+ * General Public License for more details.                               *
+ *                                                                        *
+ * You should have received a copy of the GNU Lesser General Public       *
+ * License along with the script.                                         *
+ * If not, see http://www.gnu.org/licenses/lgpl.html                      *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+/**
+
+ */
+class PaginateController extends \TYPO3\CMS\Fluid\Core\Widget\AbstractWidgetController {
+
+       /**
+        * @var array
+        */
+       protected $configuration = array('itemsPerPage' => 10, 'insertAbove' => FALSE, 'insertBelow' => TRUE, 'recordsLabel' => '');
+
+       /**
+        * @var \TYPO3\CMS\Extbase\Persistence\QueryResultInterface
+        */
+       protected $objects;
+
+       /**
+        * @var integer
+        */
+       protected $currentPage = 1;
+
+       /**
+        * @var integer
+        */
+       protected $numberOfPages = 1;
+
+       /**
+        * @var integer
+        */
+       protected $offset = 0;
+
+       /**
+        * @var integer
+        */
+       protected $itemsPerPage = 0;
+
+       /**
+        * @var integer
+        */
+       protected $numberOfObjects = 0;
+
+       /**
+        * @return void
+        */
+       public function initializeAction() {
+               $this->objects = $this->widgetConfiguration['objects'];
+               $this->configuration = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($this->configuration, $this->widgetConfiguration['configuration'], TRUE);
+               $this->numberOfObjects = count($this->objects);
+               $this->numberOfPages = ceil($this->numberOfObjects / (int) $this->configuration['itemsPerPage']);
+       }
+
+       /**
+        * @param integer $currentPage
+        * @return void
+        */
+       public function indexAction($currentPage = 1) {
+               // set current page
+               $this->currentPage = (int) $currentPage;
+               if ($this->currentPage < 1) {
+                       $this->currentPage = 1;
+               }
+               if ($this->currentPage > $this->numberOfPages) {
+                       // set $modifiedObjects to NULL if the page does not exist
+                       $modifiedObjects = NULL;
+               } else {
+                       // modify query
+                       $this->itemsPerPage = (int) $this->configuration['itemsPerPage'];
+                       $query = $this->objects->getQuery();
+                       $query->setLimit($this->itemsPerPage);
+                       $this->offset = $this->itemsPerPage * ($this->currentPage - 1);
+                       if ($this->currentPage > 1) {
+                               $query->setOffset($this->offset);
+                       }
+                       $modifiedObjects = $query->execute();
+               }
+               $this->view->assign('contentArguments', array(
+                       $this->widgetConfiguration['as'] => $modifiedObjects
+               ));
+               $this->view->assign('configuration', $this->configuration);
+               $this->view->assign('pagination', $this->buildPagination());
+       }
+
+       /**
+        * Returns an array with the keys "current", "numberOfPages", "nextPage", "previousPage", "startRecord", "endRecord"
+        *
+        * @return array
+        */
+       protected function buildPagination() {
+               $endRecord = $this->offset + $this->itemsPerPage + 1;
+               if ($endRecord > $this->numberOfObjects) {
+                       $endRecord = $this->numberOfObjects;
+               }
+               $pagination = array(
+                       'current' => $this->currentPage,
+                       'numberOfPages' => $this->numberOfPages,
+                       'hasLessPages' => $this->currentPage > 1,
+                       'hasMorePages' => $this->currentPage < $this->numberOfPages,
+                       'startRecord' => $this->offset + 1,
+                       'endRecord' => $endRecord
+               );
+               if ($this->currentPage < $this->numberOfPages) {
+                       $pagination['nextPage'] = $this->currentPage + 1;
+               }
+               if ($this->currentPage > 1) {
+                       $pagination['previousPage'] = $this->currentPage - 1;
+               }
+               return $pagination;
+       }
+
+}
+
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/Be/Widget/PaginateViewHelper.php b/typo3/sysext/fluid/Classes/ViewHelpers/Be/Widget/PaginateViewHelper.php
new file mode 100644 (file)
index 0000000..fe9d37d
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+namespace TYPO3\CMS\Fluid\ViewHelpers\Be\Widget;
+
+/*                                                                        *
+ * It is free software; you can redistribute it and/or modify it under    *
+ * the terms of the GNU Lesser General Public License, either version 3   *
+ *  of the License, or (at your option) any later version.                *
+ *                                                                        *
+ *                                                                        *
+ * This script is distributed in the hope that it will be useful, but     *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
+ * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser       *
+ * General Public License for more details.                               *
+ *                                                                        *
+ * You should have received a copy of the GNU Lesser General Public       *
+ * License along with the script.                                         *
+ * If not, see http://www.gnu.org/licenses/lgpl.html                      *
+ *                                                                        *
+ * The TYPO3 project - inspiring people to share!                         *
+ *                                                                        */
+/**
+ * This ViewHelper renders a Pagination of objects for the TYPO3 Backend.
+ *
+ * = Examples =
+ *
+ * <code title="required arguments">
+ * <f:be.widget.paginate objects="{blogs}" as="paginatedBlogs">
+ * use {paginatedBlogs} as you used {blogs} before, most certainly inside
+ * a <f:for> loop.
+ * </f:be.widget.paginate>
+ * </code>
+ *
+ * <code title="full configuration">
+ * <f:be.widget.paginate objects="{blogs}" as="paginatedBlogs" configuration="{itemsPerPage: 5, insertAbove: 1, insertBelow: 0, recordsLabel: 'MyRecords'}">
+ * use {paginatedBlogs} as you used {blogs} before, most certainly inside
+ * a <f:for> loop.
+ * </f:be.widget.paginate>
+ * The recordsLabel can be used to replace the text in "Records 1 - 99" with a label of your own choice
+ * </code>
+ *
+ * = Performance characteristics =
+ *
+ * In the above examples, it looks like {blogs} contains all Blog objects, thus
+ * you might wonder if all objects were fetched from the database.
+ * However, the blogs are NOT fetched from the database until you actually use them,
+ * so the paginate ViewHelper will adjust the query sent to the database and receive
+ * only the small subset of objects.
+ * So, there is no negative performance overhead in using the Be Paginate Widget.
+ *
+ * @api
+ */
+class PaginateViewHelper extends \TYPO3\CMS\Fluid\Core\Widget\AbstractWidgetViewHelper {
+
+       /**
+        * @var \TYPO3\CMS\Fluid\ViewHelpers\Be\Widget\Controller\PaginateController
+        */
+       protected $controller;
+
+       /**
+        * @param \TYPO3\CMS\Fluid\ViewHelpers\Be\Widget\Controller\PaginateController $controller
+        * @return void
+        */
+       public function injectController(\TYPO3\CMS\Fluid\ViewHelpers\Be\Widget\Controller\PaginateController $controller) {
+               $this->controller = $controller;
+       }
+
+       /**
+        * @param \TYPO3\CMS\Extbase\Persistence\QueryResultInterface $objects
+        * @param string $as
+        * @param array $configuration
+        * @return string
+        */
+       public function render(\TYPO3\CMS\Extbase\Persistence\QueryResultInterface $objects, $as, array $configuration = array('itemsPerPage' => 10, 'insertAbove' => FALSE, 'insertBelow' => TRUE, 'recordsLabel' => '')) {
+               return $this->initiateSubRequest();
+       }
+
+}
+
+
+?>
\ No newline at end of file
index 1fe5c9e..6c98a07 100644 (file)
@@ -9,6 +9,21 @@
                        <trans-unit id="widget.pagination.next">
                                <source>next</source>
                        </trans-unit>
+                       <trans-unit id="widget.pagination.first">
+                               <source>first</source>
+                       </trans-unit>
+                       <trans-unit id="widget.pagination.last">
+                               <source>last</source>
+                       </trans-unit>
+                       <trans-unit id="widget.pagination.records">
+                               <source>Records</source>
+                       </trans-unit>
+                       <trans-unit id="widget.pagination.page">
+                               <source>Page</source>
+                       </trans-unit>
+                       <trans-unit id="widget.pagination.refresh">
+                               <source>Refresh</source>
+                       </trans-unit>
                </body>
        </file>
 </xliff>
\ No newline at end of file
diff --git a/typo3/sysext/fluid/Resources/Private/Templates/ViewHelpers/Be/Widget/Paginate/Index.html b/typo3/sysext/fluid/Resources/Private/Templates/ViewHelpers/Be/Widget/Paginate/Index.html
new file mode 100644 (file)
index 0000000..1d7637f
--- /dev/null
@@ -0,0 +1,103 @@
+<f:if condition="{configuration.insertAbove}">
+       <f:render section="paginator" arguments="{pagination: pagination, position:'top', recordsLabel: configuration.recordsLabel}" />
+</f:if>
+
+<f:renderChildren arguments="{contentArguments}" />
+
+<f:if condition="{configuration.insertBelow}">
+       <f:render section="paginator" arguments="{pagination: pagination, position:'bottom', recordsLabel: configuration.recordsLabel}" />
+</f:if>
+
+<f:section name="paginator">
+       <div id="typo3-dblist-pagination">
+               <f:if condition="{pagination.hasLessPages}">
+                       <f:then>
+                               <f:be.buttons.icon
+                                       uri="{f:widget.uri(arguments:{currentPage: 1})}"
+                                       icon="actions-view-paging-first"
+                                       title="{f:translate(key:'widget.pagination.first')}"
+                               />
+                               <f:be.buttons.icon
+                                       uri="{f:widget.uri(arguments:{currentPage: pagination.previousPage})}"
+                                       icon="actions-view-paging-previous"
+                                       title="{f:translate(key:'widget.pagination.previous')}"
+                               />
+                       </f:then>
+                       <f:else>
+                               <f:be.buttons.icon
+                                       uri=""
+                                       icon="actions-view-paging-first-disabled"
+                               />
+                               <f:be.buttons.icon
+                                       uri=""
+                                       icon="actions-view-paging-previous-disabled"
+                               />
+                       </f:else>
+               </f:if>
+               <span class="bar"> </span>
+               <span class="pageIndicator">
+                       <f:if condition="{recordsLabel}">
+                               <f:then>
+                                       {recordsLabel}
+                               </f:then>
+                               <f:else>
+                                       <f:translate key="widget.pagination.records" />
+                               </f:else>
+                       </f:if>
+                       {pagination.startRecord} - {pagination.endRecord}</span>
+               <span class="bar"> </span>
+               <span class="pageIndicator">
+                       <f:translate key="widget.pagination.page" />
+                       <span>
+                               <form id="paginator-form-{position}" onsubmit="goToPage{position}(this); return false;" style="display:inline;">
+                               <script type="text/javascript">
+                                       function goToPage{position}(formObject) {
+                                               var url = '{f:widget.uri(arguments:{currentPage: 987654321})}';
+                                               var page = formObject.elements['paginator-target-page'].value;
+                                               if (page > {pagination.numberOfPages}) {
+                                                       page = {pagination.numberOfPages};
+                                               } else if (page < 1) {
+                                                       page = 1;
+                                               }
+                                               url = url.replace('987654321', page);
+                                               self.location.href= url;
+                                       }
+                               </script>
+                               <f:form.textfield id="paginator-{position}" name="paginator-target-page" size="5" value="{pagination.current}" />
+                               </form>
+                       </span>
+                       / {pagination.numberOfPages}
+               </span>
+               <span class="bar"> </span>
+               <f:if condition="{pagination.hasMorePages}">
+                       <f:then>
+                               <f:be.buttons.icon
+                                       uri="{f:widget.uri(arguments:{currentPage: pagination.nextPage})}"
+                                       icon="actions-view-paging-next"
+                                       title="{f:translate(key:'widget.pagination.next')}"
+                               />
+                               <f:be.buttons.icon
+                                       uri="{f:widget.uri(arguments:{currentPage: pagination.numberOfPages})}"
+                                       icon="actions-view-paging-last"
+                                       title="{f:translate(key:'widget.pagination.last')}"
+                               />
+                       </f:then>
+                       <f:else>
+                               <f:be.buttons.icon
+                                       uri="{f:widget.uri(arguments:{currentPage: pagination.nextPage})}"
+                                       icon="actions-view-paging-next-disabled"
+                               />
+                               <f:be.buttons.icon
+                                       uri="{f:widget.uri(arguments:{currentPage: pagination.numberOfPages})}"
+                                       icon="actions-view-paging-last-disabled"
+                               />
+                       </f:else>
+               </f:if>
+               <span class="bar"> </span>
+               <f:be.buttons.icon
+                       uri="{f:widget.uri(arguments:{currentPage: pagination.current})}"
+                       icon="actions-system-refresh"
+                       title="{f:translate(key:'widget.pagination.refresh')}"
+               />
+       </div>
+</f:section>