[BUGFIX] Correct JS quoting in indexed_search page browser
[Packages/TYPO3.CMS.git] / typo3 / sysext / indexed_search / Classes / ViewHelpers / PageBrowsingViewHelper.php
1 <?php
2 namespace 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
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18 use TYPO3\CMS\Core\Utility\MathUtility;
19 use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
20 use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
21 use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
22 use TYPO3\CMS\Fluid\Core\ViewHelper\Facets\CompilableInterface;
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 */
31 class PageBrowsingViewHelper extends AbstractViewHelper implements CompilableInterface {
32
33 /**
34 * @var string
35 */
36 static protected $prefixId = 'tx_indexedsearch';
37
38 /**
39 * Main render function
40 *
41 * @param int $maximumNumberOfResultPages The number of page links shown
42 * @param int $numberOfResults Total number of results
43 * @param int $resultsPerPage Number of results per page
44 * @param int $currentPage The current page starting with 0
45 * @param string|NULL $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!
46 * @return string The content
47 */
48 public function render($maximumNumberOfResultPages, $numberOfResults, $resultsPerPage, $currentPage = 0, $freeIndexUid = NULL) {
49 return static::renderStatic(
50 array(
51 'maximumNumberOfResultPages' => $maximumNumberOfResultPages,
52 'numberOfResults' => $numberOfResults,
53 'resultsPerPage' => $resultsPerPage,
54 'currentPage' => $currentPage,
55 'freeIndexUid' => $freeIndexUid,
56 ),
57 $this->buildRenderChildrenClosure(),
58 $this->renderingContext
59 );
60 }
61
62 /**
63 * @param array $arguments
64 * @param callable $renderChildrenClosure
65 * @param RenderingContextInterface $renderingContext
66 *
67 * @return string
68 */
69 static public function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) {
70 $maximumNumberOfResultPages = $arguments['maximumNumberOfResultPages'];
71 $numberOfResults = $arguments['numberOfResults'];
72 $resultsPerPage = $arguments['resultsPerPage'];
73 $currentPage = $arguments['currentPage'];
74 $freeIndexUid = $arguments['freeIndexUid'];
75
76 if ($resultsPerPage <= 0) {
77 $resultsPerPage = 10;
78 }
79 $pageCount = (int)ceil($numberOfResults / $resultsPerPage);
80 // only show the result browser if more than one page is needed
81 if ($pageCount === 1) {
82 return '';
83 }
84
85 // Check if $currentPage is in range
86 $currentPage = MathUtility::forceIntegerInRange($currentPage, 0, $pageCount - 1);
87
88 $content = '';
89 // prev page
90 // show on all pages after the 1st one
91 if ($currentPage > 0) {
92 $label = LocalizationUtility::translate('displayResults.previous', 'IndexedSearch');
93 $content .= '<li>' . self::makecurrentPageSelector_link($label, $currentPage - 1, $freeIndexUid) . '</li>';
94 }
95 // Check if $maximumNumberOfResultPages is in range
96 $maximumNumberOfResultPages = MathUtility::forceIntegerInRange($maximumNumberOfResultPages, 1, $pageCount, 10);
97 // Assume $currentPage is in the middle and calculate the index limits of the result page listing
98 $minPage = $currentPage - (int)floor($maximumNumberOfResultPages / 2);
99 $maxPage = $minPage + $maximumNumberOfResultPages - 1;
100 // Check if the indexes are within the page limits
101 if ($minPage < 0) {
102 $maxPage -= $minPage;
103 $minPage = 0;
104 } elseif ($maxPage >= $pageCount) {
105 $minPage -= $maxPage - $pageCount + 1;
106 $maxPage = $pageCount - 1;
107 }
108 $pageLabel = LocalizationUtility::translate('displayResults.page', 'IndexedSearch');
109 for ($a = $minPage; $a <= $maxPage; $a++) {
110 $label = trim($pageLabel . ' ' . ($a + 1));
111 $label = self::makecurrentPageSelector_link($label, $a, $freeIndexUid);
112 if ($a === $currentPage) {
113 $content .= '<li class="tx-indexedsearch-browselist-currentPage"><strong>' . $label . '</strong></li>';
114 } else {
115 $content .= '<li>' . $label . '</li>';
116 }
117 }
118 // next link
119 if ($currentPage < $pageCount - 1) {
120 $label = LocalizationUtility::translate('displayResults.next', 'IndexedSearch');
121 $content .= '<li>' . self::makecurrentPageSelector_link($label, ($currentPage + 1), $freeIndexUid) . '</li>';
122 }
123 return '<ul class="tx-indexedsearch-browsebox">' . $content . '</ul>';
124 }
125
126 /**
127 * Used to make the link for the result-browser.
128 * Notice how the links must resubmit the form after setting the new currentPage-value in a hidden formfield.
129 *
130 * @param string $str String to wrap in <a> tag
131 * @param int $p currentPage value
132 * @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!
133 * @return string Input string wrapped in <a> tag with onclick event attribute set.
134 */
135 static protected function makecurrentPageSelector_link($str, $p, $freeIndexUid) {
136 $onclick = 'document.getElementById(' . GeneralUtility::quoteJSvalue(self::$prefixId . '_pointer') . ').value=' . GeneralUtility::quoteJSvalue($p) . ';';
137 if ($freeIndexUid !== NULL) {
138 $onclick .= 'document.getElementById(' . GeneralUtility::quoteJSvalue(self::$prefixId . '_freeIndexUid') . ').value=' . GeneralUtility::quoteJSvalue($freeIndexUid) . ';';
139 }
140 $onclick .= 'document.getElementById(' . GeneralUtility::quoteJSvalue(self::$prefixId) . ').submit();return false;';
141 return '<a href="#" onclick="' . htmlspecialchars($onclick) . '">' . $str . '</a>';
142 }
143
144 }