1<?php 2namespace TYPO3\CMS\IndexedSearch\ViewHelpers; 3 4/* 5 * This file is part of the TYPO3 CMS project. 6 * 7 * It is free software; you can redistribute it and/or modify it under 8 * the terms of the GNU General Public License, either version 2 9 * of the License, or any later version. 10 * 11 * For the full copyright and license information, please read the 12 * LICENSE.txt file that was distributed with this source code. 13 * 14 * The TYPO3 project - inspiring people to share! 15 */ 16 17use TYPO3\CMS\Core\Utility\GeneralUtility; 18use TYPO3\CMS\Core\Utility\MathUtility; 19use TYPO3\CMS\Extbase\Utility\LocalizationUtility; 20use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface; 21use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper; 22use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic; 23 24/** 25 * Page browser for indexed search, and only useful here, as the 26 * regular pagebrowser 27 * so this is a cleaner "pi_browsebox" but not a real page browser 28 * functionality 29 * @internal 30 */ 31class PageBrowsingViewHelper extends AbstractViewHelper 32{ 33 use CompileWithRenderStatic; 34 35 /** 36 * As this ViewHelper renders HTML, the output must not be escaped. 37 * 38 * @var bool 39 */ 40 protected $escapeOutput = false; 41 42 /** 43 * @var string 44 */ 45 protected static $prefixId = 'tx_indexedsearch'; 46 47 /** 48 * Initialize arguments 49 */ 50 public function initializeArguments() 51 { 52 $this->registerArgument('maximumNumberOfResultPages', 'int', '', true); 53 $this->registerArgument('numberOfResults', 'int', '', true); 54 $this->registerArgument('resultsPerPage', 'int', '', true); 55 $this->registerArgument('currentPage', 'int', '', false, 0); 56 $this->registerArgument('freeIndexUid', 'int', ''); 57 } 58 59 /** 60 * @param array $arguments 61 * @param \Closure $renderChildrenClosure 62 * @param RenderingContextInterface $renderingContext 63 * 64 * @return string 65 */ 66 public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) 67 { 68 $maximumNumberOfResultPages = $arguments['maximumNumberOfResultPages']; 69 $numberOfResults = $arguments['numberOfResults']; 70 $resultsPerPage = $arguments['resultsPerPage']; 71 $currentPage = $arguments['currentPage']; 72 $freeIndexUid = $arguments['freeIndexUid']; 73 74 if ($resultsPerPage <= 0) { 75 $resultsPerPage = 10; 76 } 77 $pageCount = (int)ceil($numberOfResults / $resultsPerPage); 78 // only show the result browser if more than one page is needed 79 if ($pageCount === 1) { 80 return ''; 81 } 82 83 // Check if $currentPage is in range 84 $currentPage = MathUtility::forceIntegerInRange($currentPage, 0, $pageCount - 1); 85 86 $content = ''; 87 // prev page 88 // show on all pages after the 1st one 89 if ($currentPage > 0) { 90 $label = LocalizationUtility::translate('displayResults.previous', 'IndexedSearch'); 91 $content .= '<li>' . self::makecurrentPageSelector_link($label, $currentPage - 1, $freeIndexUid) . '</li>'; 92 } 93 // Check if $maximumNumberOfResultPages is in range 94 $maximumNumberOfResultPages = MathUtility::forceIntegerInRange($maximumNumberOfResultPages, 1, $pageCount, 10); 95 // Assume $currentPage is in the middle and calculate the index limits of the result page listing 96 $minPage = $currentPage - (int)floor($maximumNumberOfResultPages / 2); 97 $maxPage = $minPage + $maximumNumberOfResultPages - 1; 98 // Check if the indexes are within the page limits 99 if ($minPage < 0) { 100 $maxPage -= $minPage; 101 $minPage = 0; 102 } elseif ($maxPage >= $pageCount) { 103 $minPage -= $maxPage - $pageCount + 1; 104 $maxPage = $pageCount - 1; 105 } 106 $pageLabel = LocalizationUtility::translate('displayResults.page', 'IndexedSearch'); 107 for ($a = $minPage; $a <= $maxPage; $a++) { 108 $label = trim($pageLabel . ' ' . ($a + 1)); 109 $label = self::makecurrentPageSelector_link($label, $a, $freeIndexUid); 110 if ($a === $currentPage) { 111 $content .= '<li class="tx-indexedsearch-browselist-currentPage"><strong>' . $label . '</strong></li>'; 112 } else { 113 $content .= '<li>' . $label . '</li>'; 114 } 115 } 116 // next link 117 if ($currentPage < $pageCount - 1) { 118 $label = LocalizationUtility::translate('displayResults.next', 'IndexedSearch'); 119 $content .= '<li>' . self::makecurrentPageSelector_link($label, $currentPage + 1, $freeIndexUid) . '</li>'; 120 } 121 return '<ul class="tx-indexedsearch-browsebox">' . $content . '</ul>'; 122 } 123 124 /** 125 * Used to make the link for the result-browser. 126 * Notice how the links must resubmit the form after setting the new currentPage-value in a hidden formfield. 127 * 128 * @param string $str String to wrap in <a> tag 129 * @param int $p currentPage value 130 * @param string $freeIndexUid List of integers pointing to free indexing configurations to search. -1 represents no filtering, 0 represents TYPO3 pages only, any number above zero is a uid of an indexing configuration! 131 * @return string Input string wrapped in <a> tag with onclick event attribute set. 132 */ 133 protected static function makecurrentPageSelector_link($str, $p, $freeIndexUid) 134 { 135 $onclick = 'document.getElementById(' . GeneralUtility::quoteJSvalue(self::$prefixId . '_pointer') . ').value=' . GeneralUtility::quoteJSvalue($p) . ';'; 136 if ($freeIndexUid !== null) { 137 $onclick .= 'document.getElementById(' . GeneralUtility::quoteJSvalue(self::$prefixId . '_freeIndexUid') . ').value=' . GeneralUtility::quoteJSvalue($freeIndexUid) . ';'; 138 } 139 $onclick .= 'document.getElementById(' . GeneralUtility::quoteJSvalue(self::$prefixId) . ').submit();return false;'; 140 return '<a href="#" onclick="' . htmlspecialchars($onclick) . '">' . htmlspecialchars($str) . '</a>'; 141 } 142} 143