[FEATURE] Indexed Search: Add additional extbase plugin
authorBenjamin Mack <benni@typo3.org>
Sun, 31 Jul 2011 14:17:23 +0000 (16:17 +0200)
committerSteffen Ritter <info@rs-websystems.de>
Sun, 18 Dec 2011 10:19:20 +0000 (11:19 +0100)
Introduces a new plugin (pi2) with fluid and extbase that
separates the DB logic (Repository) and the output
(fluid-based now) from the rest (searchcontroller).
However, there is no real "repository" that works as
a regular repository. Additionally, some options
have been renamed.
This is still not completely tested and a work-in-progress,
but the feature-set should be complete. This feature is also
ready for the MySQL Fulltext Indexed Search.

Change-Id: I8ed4a3e5f09db64d560d0a44b4a7c51c6ec80481
Resolves: #28612
Releases: 4.7
Reviewed-on: http://review.typo3.org/3926
Reviewed-by: Stefan Neufeind
Reviewed-by: Dominik Mathern
Tested-by: Dominik Mathern
Reviewed-by: Steffen Ritter
Tested-by: Steffen Ritter
16 files changed:
typo3/sysext/indexed_search/Classes/Controller/SearchController.php [new file with mode: 0644]
typo3/sysext/indexed_search/Classes/Domain/Repository/IndexSearchRepository.php [new file with mode: 0644]
typo3/sysext/indexed_search/Classes/ViewHelpers/PageBrowsingResultsViewHelper.php [new file with mode: 0644]
typo3/sysext/indexed_search/Classes/ViewHelpers/PageBrowsingViewHelper.php [new file with mode: 0644]
typo3/sysext/indexed_search/Configuration/TypoScript/constants.txt [new file with mode: 0644]
typo3/sysext/indexed_search/Configuration/TypoScript/setup.txt [new file with mode: 0644]
typo3/sysext/indexed_search/Resources/Private/Language/locallang.xml [new file with mode: 0755]
typo3/sysext/indexed_search/Resources/Private/Partials/Rules.html [new file with mode: 0644]
typo3/sysext/indexed_search/Resources/Private/Partials/Searchresult.html [new file with mode: 0644]
typo3/sysext/indexed_search/Resources/Private/Templates/Search/Form.html [new file with mode: 0644]
typo3/sysext/indexed_search/Resources/Private/Templates/Search/Search.html [new file with mode: 0644]
typo3/sysext/indexed_search/ext_autoload.php
typo3/sysext/indexed_search/ext_emconf.php
typo3/sysext/indexed_search/ext_localconf.php
typo3/sysext/indexed_search/ext_tables.php
typo3/sysext/indexed_search/ext_typoscript_setup.txt

diff --git a/typo3/sysext/indexed_search/Classes/Controller/SearchController.php b/typo3/sysext/indexed_search/Classes/Controller/SearchController.php
new file mode 100644 (file)
index 0000000..04d1db0
--- /dev/null
@@ -0,0 +1,1587 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2011 Benjamin Mack (benni@typo3.org)
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+/**
+ * Index search frontend
+ *
+ * Creates a searchform for indexed search. Indexing must be enabled
+ * for this to make sense.
+ *
+ * @author     Kasper Skårhøj <kasperYYYY@typo3.com>
+ * @author     Christian Jul Jensen <christian@typo3.com>
+ * @author     Benjamin Mack <benni@typo3.org>
+ *
+ * The following variables can be sent from the form
+ *
+ * _sections
+ * _freeIndexUid
+ * pointer
+ * sword
+ * sword_prev
+ * sword_prev_include
+ * type
+ * defOp
+ * media
+ * lang
+ * sections
+ * freeIndexUid
+ * order
+ * desc
+ * results
+ * group
+ * extResume
+ * submit_button
+ */
+class Tx_IndexedSearch_Controller_SearchController extends Tx_Extbase_MVC_Controller_ActionController {
+
+
+               // previously known as $this->piVars['sword']
+       protected $sword = NULL;
+       protected $searchWords = array();
+       protected $searchData;
+
+               // This is the id of the site root.
+               // This value may be a commalist of integer (prepared for this)
+               // Root-page PIDs to search in (rl0 field where clause, see initialize() function)
+       protected $searchRootPageIdList = 0;
+
+       protected $defaultResultNumber = 10;
+
+
+       /**
+        * Lexer object
+        *
+        * @var Tx_IndexedSearch_Domain_Repository_IndexSearchRepository
+        */
+       protected $searchRepository = NULL;
+
+       /**
+        * Lexer object
+        *
+        * @var tx_indexedsearch_lexer
+        */
+       protected $lexerObj;
+
+               // External parser objects
+       protected $externalParsers = array();
+
+               // Will hold the first row in result - used to calculate relative hit-ratings.
+       protected $firstRow = array();
+
+               // Domain records (needed ?)
+       protected $domainRecords = array();
+               // Required fe_groups memberships for display of a result.
+       protected $requiredFrontendUsergroups = array();
+               // Page tree sections for search result.
+       protected $resultSections = array();
+               // Caching of page path
+       protected $pathCache = array();
+               // Storage of icons
+       protected $iconFileNameCache = array();
+               // Indexer configuration, coming from $GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['indexed_search']
+       protected $indexerConfig = array();
+
+       /**
+        * sets up all necessary object for searching
+        *
+        * @param array $searchData The incoming search parameters
+        * @return array Search parameters
+        */
+       public function initialize($searchData = array()) {
+               if (!is_array($searchData)) {
+                       $searchData = array();
+               }
+
+                       // setting default values
+               if (is_array($this->settings['defaultOptions'])) {
+                       $searchData = array_merge($this->settings['defaultOptions'], $searchData);
+               }
+
+
+                       // Indexer configuration from Extension Manager interface:
+               $this->indexerConfig = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['indexed_search']);
+               $this->enableMetaphoneSearch = $this->indexerConfig['enableMetaphoneSearch'] ? TRUE : FALSE;
+
+               $this->initializeExternalParsers();
+
+                       // If "_sections" is set, this value overrides any existing value.
+               if ($searchData['_sections']) {
+                       $searchData['sections'] = $searchData['_sections'];
+               }
+
+                       // If "_sections" is set, this value overrides any existing value.
+               if ($searchData['_freeIndexUid'] !== '' && $searchData['_freeIndexUid'] !== '_') {
+                       $searchData['freeIndexUid'] = $searchData['_freeIndexUid'];
+               }
+
+               $searchData['results'] = t3lib_div::intInRange($searchData['results'], 1, 100000, $this->defaultResultNumber);
+
+
+                       // This gets the search-words into the $searchWordArray
+               $this->sword = $searchData['sword'];
+
+                       // Add previous search words to current
+               if ($searchData['sword_prev_include'] && $searchData['sword_prev']) {
+                       $this->sword = trim($searchData['sword_prev']) . ' ' . $this->sword;
+               }
+
+               $this->searchWords = $this->getSearchWords($searchData['defaultOperand']);
+
+
+                       // This is the id of the site root.
+                       // This value may be a commalist of integer (prepared for this)
+               $this->searchRootPageIdList = intval($GLOBALS['TSFE']->config['rootLine'][0]['uid']);
+
+                       // Setting the list of root PIDs for the search. Notice, these page IDs MUST
+                       // have a TypoScript template with root flag on them! Basically this list is used
+                       // to select on the "rl0" field and page ids are registered as "rl0" only if
+                       // a TypoScript template record with root flag is there.
+                       // This happens AFTER the use of $this->searchRootPageIdList above because
+                       // the above will then fetch the menu for the CURRENT site - regardless
+                       // of this kind of searching here. Thus a general search will lookup in
+                       // the WHOLE database while a specific section search will take the current sections.
+               if ($this->settings['rootPidList']) {
+                       $this->searchRootPageIdList = implode(',', t3lib_div::intExplode(',', $this->settings['rootPidList']));
+               }
+
+               $this->searchRepository = t3lib_div::makeInstance('Tx_IndexedSearch_Domain_Repository_IndexSearchRepository');
+               $this->searchRepository->initialize($this->settings, $searchData, $this->externalParsers, $this->searchRootPageIdList);
+
+               $this->searchData = $searchData;
+
+                       // Calling hook for modification of initialized content
+               if ($hookObj = $this->hookRequest('initialize_postProc')) {
+                       $hookObj->initialize_postProc();
+               }
+               return $searchData;
+       }
+
+
+       /**
+        * Performs the search, the display and writing stats
+        *
+        * @param array $search the search parameters, an associative array
+        * @return void
+        * @dontvalidate $search
+        */
+       public function searchAction($search = array()) {
+               $searchData = $this->initialize($search);
+
+                       // Find free index uid:
+               $freeIndexUid = $searchData['freeIndexUid'];
+               if ($freeIndexUid == -2) {
+                       $freeIndexUid = $this->settings['defaultFreeIndexUidList'];
+               } elseif (!isset($searchData['freeIndexUid'])) {
+                               // index configuration is disabled
+                       $freeIndexUid = -1;
+               }
+
+               $indexCfgs = t3lib_div::intExplode(',', $freeIndexUid);
+
+               $resultsets = array();
+               foreach ($indexCfgs as $freeIndexUid) {
+
+                               // Get result rows
+                       $tstamp1 = t3lib_div::milliseconds();
+                       if ($hookObj = $this->hookRequest('getResultRows')) {
+                               $resultData = $hookObj->getResultRows($this->searchWords, $freeIndexUid);
+                       } else {
+                               $resultData = $this->searchRepository->doSearch($this->searchWords, $freeIndexUid);
+                       }
+
+                               // Display search results
+                       $tstamp2 = t3lib_div::milliseconds();
+                       if ($hookObj = $this->hookRequest('getDisplayResults')) {
+                               $resultsets[$freeIndexUid] = $hookObj->getDisplayResults($this->searchWords, $resultData, $freeIndexUid);
+                       } else {
+                               $resultsets[$freeIndexUid] = $this->getDisplayResults($this->searchWords, $resultData, $freeIndexUid);
+                       }
+
+                       $tstamp3 = t3lib_div::milliseconds();
+
+                               // Create header if we are searching more than one indexing configuration
+                       if (count($indexCfgs) > 1) {
+                               if ($freeIndexUid > 0) {
+                                       $indexCfgRec = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
+                                               'title',
+                                               'index_config',
+                                               'uid=' . intval($freeIndexUid) . $GLOBALS['TSFE']->cObj->enableFields('index_config')
+                                       );
+                                       $categoryTitle = $indexCfgRec['title'];
+                               } else {
+                                       $categoryTitle = Tx_Extbase_Utility_Localization::translate('indexingConfigurationHeader.' . $freeIndexUid, 'indexed_search');
+                               }
+                               $resultsets[$freeIndexUid]['categoryTitle'] = $categoryTitle;
+                       }
+
+                               // Write search statistics
+                       $this->writeSearchStat($searchData, $this->searchWords, $resultData['count'], array($tstamp1, $tstamp2, $tstamp3));
+               }
+               $this->view->assign('resultsets', $resultsets);
+               $this->view->assign('searchParams', $searchData);
+               $this->view->assign('searchWords', $this->searchWords);
+       }
+
+
+
+       /****************************************
+        * functions to make the result rows and result sets
+        * ready for the output
+        ***************************************/
+
+
+       /**
+        * Compiles the HTML display of the incoming array of result rows.
+        *
+        * @param array $searchWords Search words array (for display of text describing what was searched for)
+        * @param array $resultData Array with result rows, count, first row.
+        * @param integer $freeIndexUid Pointing to which indexing configuration you want to search in. -1 means no filtering. 0 means only regular indexed content.
+        * @return array
+        */
+       protected function getDisplayResults($searchWords, $resultData, $freeIndexUid = -1) {
+               $result = array(
+                       'count' => $resultData['count'],
+                       'searchWords' => $searchWords
+               );
+
+                       // Perform display of result rows array
+               if ($resultData) {
+                               // Set first selected row (for calculation of ranking later)
+                       $this->firstRow = $resultData['firstRow'];
+
+                               // Result display here
+                       $result['rows'] = $this->compileResultRows($resultData['resultRows'], $freeIndexUid);
+                       $result['affectedSections'] = $this->resultSections;
+                               // Browsing box
+                       if ($resultData['count']) {
+
+                                       // could we get this in the view?
+                               if ($this->searchData['group'] == 'sections' && $freeIndexUid <= 0) {
+                                       $result['sectionText'] = sprintf(Tx_Extbase_Utility_Localization::translate('result.' . (count($this->resultSections) > 1 ? 'inNsections' : 'inNsection'), 'indexed_search'), count($this->resultSections));
+                               }
+                       }
+               }
+
+                       // Print a message telling which words in which sections we searched for
+               if (substr($this->searchData['sections'], 0, 2) == 'rl') {
+                       $result['searchedInSectionInfo'] = Tx_Extbase_Utility_Localization::translate('result.inSection', 'indexed_search')
+                        . ' "' . substr($this->getPathFromPageId(substr($this->searchData['sections'], 4)), 1) . '"';
+               }
+               return $result;
+       }
+
+       /**
+        * Takes the array with resultrows as input and returns the result-HTML-code
+        * Takes the "group" var into account: Makes a "section" or "flat" display.
+        *
+        * @param array $resultRows Result rows
+        * @param integer $freeIndexUid Pointing to which indexing configuration you want to search in. -1 means no filtering. 0 means only regular indexed content.
+        * @return string HTML
+        */
+       protected function compileResultRows($resultRows, $freeIndexUid = -1) {
+               $finalResultRows = array();
+
+                       // Transfer result rows to new variable,
+                       // performing some mapping of sub-results etc.
+               $newResultRows = array();
+               foreach ($resultRows as $row) {
+                       $id = md5($row['phash_grouping']);
+                       if (is_array($newResultRows[$id])) {
+                                       // swapping:
+                               if (!$newResultRows[$id]['show_resume'] && $row['show_resume']) {
+                                               // Remove old
+                                       $subrows = $newResultRows[$id]['_sub'];
+                                       unset($newResultRows[$id]['_sub']);
+                                       $subrows[] = $newResultRows[$id];
+
+                                               // Insert new:
+                                       $newResultRows[$id] = $row;
+                                       $newResultRows[$id]['_sub'] = $subrows;
+                               } else {
+                                       $newResultRows[$id]['_sub'][] = $row;
+                               }
+                       } else {
+                               $newResultRows[$id] = $row;
+                       }
+               }
+               $resultRows = $newResultRows;
+               $this->resultSections = array();
+
+               if ($freeIndexUid <= 0 && $this->searchData['group'] == 'sections') {
+                       $rl2flag = substr($this->searchData['sections'], 0, 2) == 'rl';
+                       $sections = array();
+                       foreach ($resultRows as $row) {
+                               $id = $row['rl0'].'-'.$row['rl1'].($rl2flag?'-'.$row['rl2']:'');
+                               $sections[$id][] = $row;
+                       }
+
+                       $this->resultSections = array();
+
+                       foreach ($sections as $id => $resultRows) {
+                               $rlParts = explode('-', $id);
+                               if ($rlParts[2]) {
+                                       $theId = $rlParts[2];
+                                       $theRLid = 'rl2_' . $rlParts[2];
+                               } elseif ($rlParts[1]) {
+                                       $theId = $rlParts[1];
+                                       $theRLid = 'rl1_' . $rlParts[1];
+                               } else {
+                                       $theId = $rlParts[0];
+                                       $theRLid = '0';
+                               }
+
+                               $sectionName = $this->getPathFromPageId($theId);
+                               $sectionName = ltrim($sectionName, '/');
+
+                               if (!trim($sectionName)) {
+                                       $sectionTitleLinked = Tx_Extbase_Utility_Localization::translate('result.unnamedSection', 'indexed_search') . ':';
+                               } else {
+                                       $onclick = 'document.'.$this->prefixId.'[\''.$this->prefixId.'[_sections]\'].value=\''.$theRLid.'\';document.'.$this->prefixId.'.submit();return false;';
+                                       $sectionTitleLinked = '<a href="#" onclick="'.htmlspecialchars($onclick).'">'.htmlspecialchars($sectionName).':</a>';
+                               }
+                               $this->resultSections[$id] = array($sectionName, count($resultRows));
+
+                                       // Add section header
+                               $finalResultRows[] = array(
+                                       'isSectionHeader' => TRUE,
+                                       'numResultRows'   => count($resultRows),
+                                       'anchorName'      => 'anchor_' . md5($id),
+                                       'sectionTitle'    => $sectionTitleLinked
+                               );
+
+                                       // Render result rows
+                               foreach ($resultRows as $row) {
+                                       $finalResultRows[] = $this->compileSingleResultRow($row);
+                               }
+                       }
+               } else {
+                               // flat mode or no sections at all
+                       foreach ($resultRows as $row) {
+                               $finalResultRows[] = $this->compileSingleResultRow($row);
+                       }
+               }
+               return $finalResultRows;
+       }
+
+
+
+       /**
+        * This prints a single result row, including a recursive call for subrows.
+        *
+        * @param array $row Search result row
+        * @param integer $headerOnly 1=Display only header (for sub-rows!), 2=nothing at all
+        * @return string HTML code
+        */
+       protected function compileSingleResultRow($row, $headerOnly = 0) {
+               $specRowConf = $this->getSpecialConfigForResultRow($row);
+
+               $resultData = $row;
+               $resultData['headerOnly'] = $headerOnly;
+               $resultData['CSSsuffix'] = $specRowConf['CSSsuffix'] ? '-' . $specRowConf['CSSsuffix'] : '';
+
+               if ($this->multiplePagesType($row['item_type'])) {
+                       $dat = unserialize($row['cHashParams']);
+                       $pp = explode('-', $dat['key']);
+                       if ($pp[0] != $pp[1]) {
+                               $resultData['titleaddition'] = ', ' . Tx_Extbase_Utility_Localization::translate('result.page', 'indexed_search') . ' ' . $dat['key'];
+                       } else {
+                               $resultData['titleaddition'] = ', ' . Tx_Extbase_Utility_Localization::translate('result.pages', 'indexed_search') . ' ' . $pp[0];
+                       }
+               }
+               $title = $resultData['item_title'] . $resultData['titleaddition'];
+               $title = htmlspecialchars($title);
+
+
+                       // If external media, link to the media-file instead.
+               if ($row['item_type']) {
+                       if ($row['show_resume']) {
+                                       // Can link directly.
+                               $targetAttribute = '';
+                               if ($GLOBALS['TSFE']->config['config']['fileTarget']) {
+                                       $targetAttribute = ' target="' . htmlspecialchars($GLOBALS['TSFE']->config['config']['fileTarget']) . '"';
+                               }
+                               $title = '<a href="' . htmlspecialchars($row['data_filename']) . '"' . $targetAttribute . '>' .
+                                       $title .
+                                       '</a>';
+                       } else {
+                                       // Suspicious, so linking to page instead...
+                               $copiedRow = $row;
+                               unset($copiedRow['cHashParams']);
+                               $title = $this->linkPage($row['page_id'], $title, $copiedRow);
+                       }
+               } else {
+                               // Else the page:
+
+                               // Prepare search words for markup in content:
+                       if ($this->settings['forwardSearchWordsInResultLink']) {
+                               $markUpSwParams = array('no_cache' => 1);
+                               foreach ($this->sWArr as $d) {
+                                       $markUpSwParams['sword_list'][] = $d['sword'];
+                               }
+                       } else {
+                               $markUpSwParams = array();
+                       }
+                       $title = $this->linkPage($row['data_page_id'], $title, $row, $markUpSwParams);
+               }
+
+               $resultData['title']       = $title;
+               $resultData['icon']        = $this->makeItemTypeIcon($row['item_type'], '', $specRowConf);
+               $resultData['rating']      = $this->makeRating($row);
+               $resultData['description'] = $this->makeDescription($row, ($this->searchData['extResume'] && !$headerOnly) ? 0 : 1);
+               $resultData['language']    = $this->makeLanguageIndication($row);
+
+               $resultData['size']     = t3lib_div::formatSize($row['item_size']);
+               $resultData['created']  = $row['item_crdate'];
+               $resultData['modified'] = $row['item_mtime'];
+
+               $pI = parse_url($row['data_filename']);
+               if ($pI['scheme']) {
+                       $targetAttribute = '';
+                       if ($GLOBALS['TSFE']->config['config']['fileTarget']) {
+                               $targetAttribute = ' target="' . htmlspecialchars($GLOBALS['TSFE']->config['config']['fileTarget']) . '"';
+                       }
+                       $resultData['path'] = '<a href="' . htmlspecialchars($row['data_filename']) . '"' . $targetAttribute . '>' .
+                               htmlspecialchars($row['data_filename']) .
+                               '</a>';
+               } else {
+                       $pathId = $row['data_page_id'] ? $row['data_page_id'] : $row['page_id'];
+                       $pathMP = $row['data_page_id'] ? $row['data_page_mp'] : '';
+                       $pathStr = htmlspecialchars($this->getPathFromPageId($pathId, $pathMP));
+                       $resultData['path'] = $this->linkPage($pathId, $pathStr, array(
+                               'cHashParams'      => $row['cHashParams'],
+                               'data_page_type'   => $row['data_page_type'],
+                               'data_page_mp'     => $pathMP,
+                               'sys_language_uid' => $row['sys_language_uid'],
+                       ));
+
+                               // check if the access is restricted
+                       if (is_array($this->requiredFrontendUsergroups[$id]) && count($this->requiredFrontendUsergroups[$id])) {
+                               $resultData['access'] = '<img src="' . t3lib_extMgm::siteRelPath('indexed_search') . 'pi/res/locked.gif" width="12" height="15" vspace="5" title="' . sprintf(Tx_Extbase_Utility_Localization::translate('result.memberGroups', 'indexed_search'), implode(',', array_unique($this->requiredFrontendUsergroups[$id]))) . '" alt="" />';
+                       }
+               }
+
+                       // If there are subrows (eg. subpages in a PDF-file or if a duplicate page
+                       // is selected due to user-login (phash_grouping))
+               if (is_array($row['_sub'])) {
+                       $resultData['subresults'] = array();
+                       if ($this->multiplePagesType($row['item_type'])) {
+                               $resultData['subresults']['header'] = Tx_Extbase_Utility_Localization::translate('result.otherMatching', 'indexed_search');
+                               foreach ($row['_sub'] as $subRow) {
+                                       $resultData['subresults']['items'][] = $this->compileSingleResultRow($subRow, 1);
+                               }
+                       } else {
+                               $resultData['subresults']['header'] = Tx_Extbase_Utility_Localization::translate('result.otherMatching', 'indexed_search');
+                               $resultData['subresults']['info'] = Tx_Extbase_Utility_Localization::translate('result.otherPageAsWell', 'indexed_search');
+                       }
+               }
+
+               return $resultData;
+       }
+
+       /**
+        * Returns configuration from TypoScript for result row based
+        * on ID / location in page tree!
+        *
+        * @param array $row Result row
+        * @return array Configuration array
+        */
+       protected function getSpecialConfigForResultRow($row) {
+               $pathId = $row['data_page_id'] ? $row['data_page_id'] : $row['page_id'];
+               $pathMP = $row['data_page_id'] ? $row['data_page_mp'] : '';
+
+               $rl = $GLOBALS['TSFE']->sys_page->getRootLine($pathId, $pathMP);
+               $specConf = $this->settings['specialConfiguration.']['0.'];
+               if (is_array($rl)) {
+                       foreach ($rl as $dat) {
+                               if (is_array($this->conf['specialConfiguration.'][$dat['uid'] . '.'])) {
+                                       $specConf = $this->conf['specialConfiguration.'][$dat['uid'] . '.'];
+                                       $specConf['_pid'] = $dat['uid'];
+                                       break;
+                               }
+                       }
+               }
+
+               return $specConf;
+       }
+
+       /**
+        * Return the rating-HTML code for the result row. This makes use of the $this->firstRow
+        *
+        * @param array $row Result row array
+        * @return string String showing ranking value
+        * @todo can this be a ViewHelper?
+        */
+       protected function makeRating($row) {
+
+               switch((string) $this->searchData['sortOrder']) {
+
+                               // Number of occurencies on page
+                       case 'rank_count':
+                               return $row['order_val'] . ' ' . Tx_Extbase_Utility_Localization::translate('result.ratingMatches', 'indexed_search');
+                       break;
+
+                               // Close to top of page
+                       case 'rank_first':
+                               return ceil(t3lib_div::intInRange(255 - $row['order_val'], 1, 255) / 255 * 100) . '%';
+                       break;
+
+                               // Based on priority assigned to <title> / <meta-keywords> / <meta-description> / <body>
+                       case 'rank_flag':
+                               if ($this->firstRow['order_val2']) {
+                                        // (3 MSB bit, 224 is highest value of order_val1 currently)
+                                       $base = $row['order_val1'] * 256;
+                                               // 15-3 MSB = 12
+                                       $freqNumber = $row['order_val2'] / $this->firstRow['order_val2'] * pow(2, 12);
+                                       $total = t3lib_div::intInRange($base + $freqNumber, 0, 32767);
+                                       return ceil(log($total) / log(32767) * 100) . '%';
+                               }
+                       break;
+
+                               // Based on frequency
+                       case 'rank_freq':
+                               $max = 10000;
+                               $total = t3lib_div::intInRange($row['order_val'], 0, $max);
+                               return ceil(log($total) / log($max) * 100) . '%';
+                       break;
+
+                               // Based on creation date
+                       case 'crdate':
+                               return $this->cObj->calcAge($GLOBALS['EXEC_TIME'] - $row['item_crdate'], 0);
+                       break;
+
+                               // Based on modification time
+                       case 'mtime':
+                               return $this->cObj->calcAge($GLOBALS['EXEC_TIME'] - $row['item_mtime'], 0);
+                       break;
+
+                               // fx. title
+                       default:
+                               return ' ';
+                       break;
+               }
+       }
+
+
+
+       /**
+        * Returns the HTML code for language indication.
+        *
+        * @param array $row Result row
+        * @return string HTML code for result row.
+        */
+       protected function makeLanguageIndication($row) {
+               $output = '&nbsp;';
+
+                       // If search result is a TYPO3 page:
+               if ((string) $row['item_type'] === '0') {
+
+                               // If TypoScript is used to render the flag:
+                       if (is_array($this->settings['flagRendering.'])) {
+                               $cObj = t3lib_div::makeInstance('tslib_cObj');
+                               $cObj->setCurrentVal($row['sys_language_uid']);
+                               $output = $cObj->cObjGetSingle($this->settings['flagRendering'], $this->settings['flagRendering.']);
+                       } else {
+                                       // ... otherwise, get flag from sys_language record:
+                               $languageRow = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
+                                       'flag, title',
+                                       'sys_language',
+                                       'uid=' . intval($row['sys_language_uid'])
+                                        . $GLOBALS['TSFE']->cObj->enableFields('sys_language')
+                               );
+
+                                       // Flag code:
+                               $flag = $languageRow['flag'];
+                               if ($flag) {
+
+                                               // FIXME not all flags from typo3/gfx/flags
+                                               // are available in media/flags/
+                                       $file = substr(PATH_tslib, strlen(PATH_site)) . 'media/flags/flag_' . $flag;
+                                       $imgInfo = @getimagesize(PATH_site . $file);
+
+                                       // original
+                                       # $file = TYPO3_mainDir.'gfx/flags/'.$flag;
+                                       # $imgInfo = @getimagesize(PATH_site.$file);
+
+                                       if (is_array($imgInfo)) {
+                                               $output = '<img src="' . $file . '" ' . $imgInfo[3] . ' title="' . htmlspecialchars($languageRow['title']) . '" alt="' . htmlspecialchars($languageRow['title']) . '" />';
+                                       }
+                               }
+                       }
+               }
+               return $output;
+       }
+
+
+
+       /**
+        * Return icon for file extension
+        *
+        * @param string $imageType File extension / item type
+        * @param string $alt Title attribute value in icon.
+        * @param array $specRowConf TypoScript configuration specifically for search result.
+        * @return string <img> tag for icon
+        */
+       function makeItemTypeIcon($imageType, $alt, $specRowConf) {
+
+                       // Build compound key if item type is 0, iconRendering is not used
+                       // and specConfs.[pid].pageIcon was set in TS
+               if ($imageType === '0' && $specRowConf['_pid'] && is_array($specRowConf['pageIcon.']) && !is_array($this->settings['iconRendering.'])) {
+                       $imageType .= ':' . $specRowConf['_pid'];
+               }
+
+               if (!isset($this->iconFileNameCache[$imageType])) {
+                       $this->iconFileNameCache[$imageType] = '';
+
+                               // If TypoScript is used to render the icon:
+                       if (is_array($this->settings['iconRendering.'])) {
+                               $this->cObj->setCurrentVal($imageType);
+                               $this->iconFileNameCache[$imageType] = $this->cObj->cObjGetSingle($this->settings['iconRendering'], $this->settings['iconRendering.']);
+
+                               // ... otherwise, get flag from sys_language record:
+                       } else {
+
+                                       // Default creation / finding of icon:
+                               $icon = '';
+                               if ($imageType === '0' || substr($imageType, 0, 2) == '0:') {
+                                       if (is_array($specRowConf['pageIcon.'])) {
+                                               $this->iconFileNameCache[$imageType] = $this->cObj->IMAGE($specRowConf['pageIcon.']);
+                                       } else {
+                                               $icon = 'EXT:indexed_search/pi/res/pages.gif';
+                                       }
+                               } elseif ($this->externalParsers[$imageType]) {
+                                       $icon = $this->externalParsers[$imageType]->getIcon($imageType);
+                               }
+
+                               if ($icon) {
+                                       $fullPath = t3lib_div::getFileAbsFileName($icon);
+
+                                       if ($fullPath) {
+                                               $info = @getimagesize($fullPath);
+                                               $iconPath = substr($fullPath, strlen(PATH_site));
+                                               $this->iconFileNameCache[$imageType] = (is_array($info)) ? '<img src="' . $iconPath . '" ' . $info[3] . ' title="' . htmlspecialchars($alt) . '" alt="" />' : '';
+                                       }
+                               }
+                       }
+               }
+               return $this->iconFileNameCache[$imageType];
+       }
+
+
+
+       /**
+        * Returns the resume for the search-result.
+        *
+        * @param array $row Search result row
+        * @param boolean $noMarkup If noMarkup is FALSE, then the index_fulltext table is used to select the content of the page, split it with regex to display the search words in the text.
+        * @param integer $length String length
+        * @return string HTML string
+        * @todo overwork this
+        */
+       protected function makeDescription($row, $noMarkup = FALSE, $lgd = 180) {
+               if ($row['show_resume']) {
+                       if (!$noMarkup) {
+                               $markedSW = '';
+                               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'index_fulltext', 'phash=' . intval($row['phash']));
+                               if ($ftdrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
+                                               // Cut HTTP references after some length
+                                       $content = preg_replace('/(http:\/\/[^ ]{60})([^ ]+)/i', '$1...', $ftdrow['fulltextdata']);
+                                       $markedSW = $this->markupSWpartsOfString($content);
+                               }
+                               $GLOBALS['TYPO3_DB']->sql_free_result($res);
+                       }
+
+                       if (!trim($markedSW)) {
+                               $outputStr = $GLOBALS['TSFE']->csConvObj->crop('utf-8', $row['item_description'], $length);
+                               $outputStr = htmlspecialchars($outputStr);
+                       }
+                       $output = $outputStr ? $outputStr : $markedSW;
+                       $output = $GLOBALS['TSFE']->csConv($output, 'utf-8');
+               } else {
+                       $output = '<span class="noResume">' . Tx_Extbase_Utility_Localization::translate('result.noResume', 'indexed_search') . '</span>';
+               }
+
+               return $output;
+       }
+
+       /**
+        * Marks up the search words from $this->sWarr in the $str with a color.
+        *
+        * @param string $str Text in which to find and mark up search words. This text is assumed to be UTF-8 like the search words internally is.
+        * @return string Processed content
+        */
+       protected function markupSWpartsOfString($str) {
+
+                       // Init:
+               $str = str_replace('&nbsp;',' ',t3lib_parsehtml::bidir_htmlspecialchars($str,-1));
+               $str = preg_replace('/\s\s+/',' ',$str);
+               $swForReg = array();
+
+                       // Prepare search words for regex:
+               foreach ($this->sWArr as $d) {
+                       $swForReg[] = preg_quote($d['sword'],'/');
+               }
+               $regExString = '('.implode('|',$swForReg).')';
+
+                       // Split and combine:
+               $parts = preg_split('/'.$regExString.'/i', ' '.$str.' ', 20000, PREG_SPLIT_DELIM_CAPTURE);
+// debug($parts,$regExString);
+                       // Constants:
+               $summaryMax = 300;
+               $postPreLgd = 60;
+               $postPreLgd_offset = 5;
+               $divider = ' ... ';
+
+               $occurencies = (count($parts)-1)/2;
+               if ($occurencies) {
+                       $postPreLgd = t3lib_div::intInRange($summaryMax / $occurencies, $postPreLgd, $summaryMax / 2);
+               }
+
+                       // Variable:
+               $summaryLgd = 0;
+               $output = array();
+
+                       // Shorten in-between strings:
+               foreach ($parts as $k => $strP) {
+                       if (($k % 2) == 0) {
+
+                                       // Find length of the summary part:
+                               $strLen = $GLOBALS['TSFE']->csConvObj->strlen('utf-8', $parts[$k]);
+                               $output[$k] = $parts[$k];
+
+                                       // Possibly shorten string:
+                               if (!$k) {      // First entry at all (only cropped on the frontside)
+                                       if ($strLen > $postPreLgd) {
+                                               $output[$k] = $divider.preg_replace('/^[^[:space:]]+[[:space:]]/', '', $GLOBALS['TSFE']->csConvObj->crop('utf-8', $parts[$k], -($postPreLgd - $postPreLgd_offset)));
+                                       }
+                               } elseif ($summaryLgd > $summaryMax || !isset($parts[$k+1])) {  // In case summary length is exceed OR if there are no more entries at all:
+                                       if ($strLen > $postPreLgd) {
+                                               $output[$k] = preg_replace('/[[:space:]][^[:space:]]+$/','',$GLOBALS['TSFE']->csConvObj->crop('utf-8', $parts[$k], $postPreLgd - $postPreLgd_offset)) . $divider;
+                                       }
+                               } else {        // In-between search words:
+                                       if ($strLen > $postPreLgd * 2) {
+                                               $output[$k] = preg_replace('/[[:space:]][^[:space:]]+$/','',$GLOBALS['TSFE']->csConvObj->crop('utf-8', $parts[$k], $postPreLgd - $postPreLgd_offset)).
+                                                                               $divider.
+                                                                               preg_replace('/^[^[:space:]]+[[:space:]]/','',$GLOBALS['TSFE']->csConvObj->crop('utf-8', $parts[$k], -($postPreLgd - $postPreLgd_offset)));
+                                       }
+                               }
+                               $summaryLgd+= $GLOBALS['TSFE']->csConvObj->strlen('utf-8', $output[$k]);
+
+                                       // Protect output:
+                               $output[$k] = htmlspecialchars($output[$k]);
+
+                                       // If summary lgd is exceed, break the process:
+                               if ($summaryLgd > $summaryMax) {
+                                       break;
+                               }
+                       } else {
+                               $summaryLgd += $GLOBALS['TSFE']->csConvObj->strlen('utf-8', $strP);
+                               $output[$k] = '<strong class="tx-indexedsearch-redMarkup">' . htmlspecialchars($parts[$k]) . '</strong>';
+                       }
+               }
+
+                       // Return result:
+               return implode('', $output);
+       }
+
+
+
+       /**
+        * Write statistics information to database for the search operation
+        *
+        * @param       array           search params
+        * @param       array           Search Word array
+        * @param       integer         Number of hits
+        * @param       integer         Milliseconds the search took
+        * @return      void
+        */
+       protected function writeSearchStat($searchParams, $searchWords, $count, $pt) {
+               $insertFields = array(
+                       'searchstring'  => $this->sword,
+                       'searchoptions' => serialize(array($searchParams, $searchWords, $pt)),
+                       'feuser_id' => intval($GLOBALS['TSFE']->fe_user->user['uid']),
+                               // cookie as set or retrieved. If people has cookies disabled this will vary all the time
+                       'cookie' => $GLOBALS['TSFE']->fe_user->id,
+                               // Remote IP address
+                       'IP'     => t3lib_div::getIndpEnv('REMOTE_ADDR'),
+                               // Number of hits on the search
+                       'hits'   => intval($count),
+                               // Time stamp
+                       'tstamp' => $GLOBALS['EXEC_TIME']                                       
+               );
+
+               $GLOBALS['TYPO3_DB']->exec_INSERTquery('index_stat_search', $insertFields);
+               $newId = $GLOBALS['TYPO3_DB']->sql_insert_id();
+
+               if ($newId) {
+                       foreach ($searchWords as $val) {
+                               $insertFields = array(
+                                       'word' => $val['sword'],        // $GLOBALS['TSFE']->csConvObj->conv_case('utf-8', $val['sword'], 'toLower'),
+                                       'index_stat_search_id' => $newId,
+                                               // Time stamp
+                                       'tstamp' => $GLOBALS['EXEC_TIME'],
+                                               // search page id for indexed search stats
+                                       'pageid' => $GLOBALS['TSFE']->id
+                               );
+
+                               $GLOBALS['TYPO3_DB']->exec_INSERTquery('index_stat_word', $insertFields);
+                       }
+               }
+       }
+
+
+
+
+       /**
+        * Splits the search word input into an array where each word is represented by an array with key "sword" holding the search word and key "oper" holding the SQL operator (eg. AND, OR)
+        *
+        * Only words with 2 or more characters are accepted
+        * Max 200 chars total
+        * Space is used to split words, "" can be used search for a whole string
+        * AND, OR and NOT are prefix words, overruling the default operator
+        * +/|/- equals AND, OR and NOT as operators.
+        * All search words are converted to lowercase.
+        *
+        * $defOp is the default operator. 1=OR, 0=AND
+        *
+        * @param boolean $defaultOperator If TRUE, the default operator will be OR, not AND
+        * @return array Search words if any found
+        */
+       protected function getSearchWords($defaultOperator) {
+                       // Shorten search-word string to max 200 bytes (does NOT take multibyte charsets into account - but never mind, shortening the string here is only a run-away feature!)
+               $searchWords = substr($this->sword, 0, 200);
+
+                       // Convert to UTF-8 + conv. entities (was also converted during indexing!)
+               $searchWords = $GLOBALS['TSFE']->csConvObj->utf8_encode($searchWords, $GLOBALS['TSFE']->metaCharset);
+               $searchWords = $GLOBALS['TSFE']->csConvObj->entities_to_utf8($searchWords, TRUE);
+
+               $sWordArray = FALSE;
+               if ($hookObj = $this->hookRequest('getSearchWords')) {
+                       $sWordArray = $hookObj->getSearchWords_splitSWords($searchWords, $defaultOperator);
+               } else {
+                               // sentence
+                       if ($this->searchDat['searchType'] == 20) {
+                               $sWordArray = array(
+                                       array(
+                                               'sword' => trim($searchWords),
+                                               'oper' => 'AND'
+                                       )
+                               );
+                       } else {
+
+                               // case-sensitive. Defines the words, which will be
+                               // operators between words
+                               $operatorTranslateTable = array(
+                                       array('+' , 'AND'),
+                                       array('|' , 'OR'),
+                                       array('-' , 'AND NOT'),
+                                               // english
+                                       // array('AND' , 'AND'),
+                                       // array('OR' , 'OR'),
+                                       // array('NOT' , 'AND NOT'),
+                                               // Add operators for various languages
+                                               // Converts the operators to UTF-8 and lowercase
+                                       array($GLOBALS['TSFE']->csConvObj->conv_case('utf-8',$GLOBALS['TSFE']->csConvObj->utf8_encode(Tx_Extbase_Utility_Localization::translate('localizedOperandAnd', 'indexed_search'), $GLOBALS['TSFE']->renderCharset), 'toLower'), 'AND'),
+                                       array($GLOBALS['TSFE']->csConvObj->conv_case('utf-8',$GLOBALS['TSFE']->csConvObj->utf8_encode(Tx_Extbase_Utility_Localization::translate('localizedOperandOr', 'indexed_search'),  $GLOBALS['TSFE']->renderCharset), 'toLower'), 'OR'),
+                                       array($GLOBALS['TSFE']->csConvObj->conv_case('utf-8',$GLOBALS['TSFE']->csConvObj->utf8_encode(Tx_Extbase_Utility_Localization::translate('localizedOperandNot', 'indexed_search'), $GLOBALS['TSFE']->renderCharset), 'toLower'), 'AND NOT'),
+                               );
+
+                               $search = t3lib_div::makeInstance('tslib_search');
+                               $search->default_operator = $defaultOperator == 1 ? 'OR' : 'AND';
+                               $search->operator_translate_table = $operatorTranslateTable;
+                               $search->register_and_explode_search_string($searchWords);
+
+                               if (is_array($search->sword_array)) {
+                                       $sWordArray = $this->procSearchWordsByLexer($search->sword_array);
+                               }
+                       }
+               }
+               return $sWordArray;
+       }
+
+       /**
+        * Post-process the search word array so it will match the words that was indexed (including case-folding if any)
+        * If any words are splitted into multiple words (eg. CJK will be!) the operator of the main word will remain.
+        *
+        * @param array $searchWords Search word array
+        * @return array Search word array, processed through lexer
+        */
+       protected function procSearchWordsByLexer($searchWords) {
+               $newSearchWords = array();
+
+                       // Init lexer (used to post-processing of search words)
+               $lexerObjRef = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['lexer'] ?
+                                               $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['lexer'] :
+                                               'EXT:indexed_search/class.lexer.php:&tx_indexedsearch_lexer';
+               $this->lexerObj = t3lib_div::getUserObj($lexerObjRef);
+
+                       // Traverse the search word array
+               foreach ($searchWords as $wordDef) {
+                               // No space in word (otherwise it might be a sentense in quotes like "there is").
+                       if (strpos($wordDef['sword'], ' ') === FALSE) {
+                                       // Split the search word by lexer:
+                               $res = $this->lexerObj->split2Words($wordDef['sword']);
+
+                                       // Traverse lexer result and add all words again:
+                               foreach ($res as $word) {
+                                       $newSearchWords[] = array(
+                                               'sword' => $word,
+                                               'oper' => $wordDef['oper']
+                                       );
+                               }
+                       } else {
+                               $newSearchWords[] = $wordDef;
+                       }
+               }
+               return $newSearchWords;
+       }
+
+
+
+
+       /**
+        * Sort options about the search form
+        *
+        * @param array $search The search data / params
+        * @return void
+        * @dontvalidate $search
+        */
+       public function formAction($search = array()) {
+               $this->initialize($search);
+
+                       // Adding search field value
+               $this->view->assign('sword', $this->sword);
+
+                       // Additonal keyword => "Add to current search words"
+               $showAdditionalKeywordSearch = ($this->settings['clearSearchBox'] && $this->settings['clearSearchBox.']['enableSubSearchCheckBox']);
+               if ($showAdditionalKeywordSearch) {
+                       $this->view->assign('previousSearchWord', ($this->settings['clearSearchBox'] ? '' : $this->sword));
+               }
+               $this->view->assign('showAdditionalKeywordSearch', $showAdditionalKeywordSearch);
+
+                       // Extended search
+               if ($search['extendedSearch']) {
+
+                               // "Search for"
+                       $allSearchTypes = $this->getAllAvailableSearchTypeOptions();
+                       $this->view->assign('allSearchTypes', $allSearchTypes);
+
+                       $allDefaultOperands = $this->getAllAvailableOperandsOptions();
+                       $this->view->assign('allDefaultOperands', $allDefaultOperands);
+
+                       $showTypeSearch = (count($allSearchTypes) || count($allDefaultOperands));
+                       $this->view->assign('showTypeSearch', $showTypeSearch);
+
+
+                               // "Search in"
+                       $allMediaTypes = $this->getAllAvailableMediaTypesOptions();
+                       $this->view->assign('allMediaTypes', $allMediaTypes);
+
+                       $allLanguageUids = $this->getAllAvailableLanguageOptions();
+                       $this->view->assign('allLanguageUids', $allLanguageUids);
+
+                       $showMediaAndLanguageSearch = (count($allMediaTypes) || count($allLanguageUids));
+                       $this->view->assign('showMediaAndLanguageSearch', $showMediaAndLanguageSearch);
+
+
+                               // Sections
+                       $allSections = $this->getAllAvailableSectionsOptions();
+                       $this->view->assign('allSections', $allSections);
+
+                               // Free Indexing Configurations
+                       $allIndexConfigurations = $this->getAllAvailableIndexConfigurationsOptions();
+                       $this->view->assign('allIndexConfigurations', $allIndexConfigurations);
+
+                               // Sorting
+                       $allSortOrders = $this->getAllAvailableSortOrderOptions();
+                       $this->view->assign('allSortOrders', $allSortOrders);
+                       $allSortDescendings = $this->getAllAvailableSortDescendingOptions();
+                       $this->view->assign('allSortDescendings', $allSortDescendings);
+                       $showSortOrders = (count($allSortOrders) || count($allSortDescendings));
+                       $this->view->assign('showSortOrders', $showSortOrders);
+
+                               // Limits
+                       $allNumberOfResults = $this->getAllAvailableNumberOfResultsOptions();
+                       $this->view->assign('allNumberOfResults', $allNumberOfResults);
+
+                       $allGroups = $this->getAllAvailableGroupOptions();
+                       $this->view->assign('allGroups', $allGroups);
+               }
+       }
+
+
+
+
+
+
+
+
+       /****************************************
+        * building together the available options for every dropdown
+        ***************************************/
+
+       /**
+        * get the values for the "type" selector
+        *
+        * @return array Associative array with options
+        */
+       protected function getAllAvailableSearchTypeOptions() {
+               $allOptions = array();
+               $types = array(0, 1, 2, 3, 10, 20);
+
+               $blindSettings = $this->settings['blind.'];
+               if (!$blindSettings['searchType']) {
+                       foreach ($types as $typeNum) {
+                               $allOptions[$typeNum] = Tx_Extbase_Utility_Localization::translate('searchTypes.' . $typeNum, 'indexed_search');
+                       }
+               }
+
+                               // Remove this option if metaphone search is disabled)
+               if (!$this->enableMetaphoneSearch) {
+                       unset ($allOptions[10]);
+               }
+
+                       // disable single entries by TypoScript
+               $allOptions = $this->removeOptionsFromOptionList($allOptions, $blindSettings['searchType.']);
+               return $allOptions;
+       }
+
+
+       /**
+        * get the values for the "defaultOperand" selector
+        *
+        * @return array Associative array with options
+        */
+       protected function getAllAvailableOperandsOptions() {
+               $allOptions = array();
+
+               $blindSettings = $this->settings['blind.'];
+               if (!$blindSettings['defaultOperand']) {
+                       $allOptions = array(
+                               0 => Tx_Extbase_Utility_Localization::translate('defaultOperands.0', 'indexed_search'),
+                               1 => Tx_Extbase_Utility_Localization::translate('defaultOperands.1', 'indexed_search')
+                       );
+               }
+
+                       // disable single entries by TypoScript
+               $allOptions = $this->removeOptionsFromOptionList($allOptions, $blindSettings['defaultOperand.']);
+               return $allOptions;
+       }
+
+       /**
+        * get the values for the "media type" selector
+        *
+        * @return array Associative array with options
+        */
+       protected function getAllAvailableMediaTypesOptions() {
+               $allOptions = array();
+               $mediaTypes = array(-1, 0, -2);
+
+               $blindSettings = $this->settings['blind.'];
+               if (!$blindSettings['mediaType']) {
+                       foreach ($mediaTypes as $mediaType) {
+                               $allOptions[$mediaType] = Tx_Extbase_Utility_Localization::translate('mediaTypes.' . $mediaType, 'indexed_search');
+                       }
+
+                               // Add media to search in:
+                       $additionalMedia = trim($this->settings['mediaList']);
+                       if (strlen($additionalMedia) > 0) {
+                               $additionalMedia = t3lib_div::trimExplode(',', $additionalMedia, TRUE);
+                       }
+
+                       foreach ($this->externalParsers as $extension => $obj) {
+                                       // Skip unwanted extensions
+                               if (count($additionalMedia) && !in_array($extension, $additionalMedia)) {
+                                       continue;
+                               }
+
+                               if ($name = $obj->searchTypeMediaTitle($extension)) {
+                                       $allOptions[$extension] = Tx_Extbase_Utility_Localization::translate('mediaTypes.' . $extension, $name);
+                               }
+                       }
+               }
+
+                       // disable single entries by TypoScript
+               $allOptions = $this->removeOptionsFromOptionList($allOptions, $blindSettings['mediaType.']);
+               return $allOptions;
+       }
+
+
+
+       /**
+        * get the values for the "language" selector
+        *
+        * @return array Associative array with options
+        */
+       protected function getAllAvailableLanguageOptions() {
+               $allOptions = array(
+                       '-1' => Tx_Extbase_Utility_Localization::translate('languageUids.-1', 'indexed_search'),
+                       '0'  => Tx_Extbase_Utility_Localization::translate('languageUids.0', 'indexed_search')
+               );
+
+               $blindSettings = $this->settings['blind.'];
+               if (!$blindSettings['languageUid']) {
+
+                               // Add search languages
+                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+                               '*',
+                               'sys_language',
+                               '1=1' . $GLOBALS['TSFE']->cObj->enableFields('sys_language')
+                       );
+                       if ($res) {
+                               while ($lang = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
+                                       $allOptions[$lang['uid']] = $lang['title'];
+                               }
+                       }
+
+                               // disable single entries by TypoScript
+                       $allOptions = $this->removeOptionsFromOptionList($allOptions, $blindSettings['languageUid.']);
+
+               } else {
+                       $allOptions = array();
+               }
+               return $allOptions;
+       }
+
+
+       /**
+        * get the values for the "section" selector
+        * Here values like "rl1_" and "rl2_" + a rootlevel 1/2 id can be added
+        *  to perform searches in rootlevel 1+2 specifically. The id-values can even
+        *  be commaseparated. Eg. "rl1_1,2" would search for stuff inside pages on
+        *  menu-level 1 which has the uid's 1 and 2.
+        *
+        * @return array Associative array with options
+        */
+       protected function getAllAvailableSectionsOptions() {
+               $allOptions = array();
+               $sections = array(0, -1, -2, -3);
+
+               $blindSettings = $this->settings['blind.'];
+               if (!$blindSettings['sections']) {
+                       foreach ($sections as $section) {
+                               $allOptions[$section] = Tx_Extbase_Utility_Localization::translate('sections.' . $section, 'indexed_search');
+                       }
+               }
+
+                       // Creating levels for section menu:
+                       // This selects the first and secondary menus for the "sections" selector - so we can search in sections and sub sections.
+               if ($this->settings['displayLevel1Sections']) {
+                       $firstLevelMenu = $this->getMenuOfPages($this->searchRootPageIdList);
+                       $labelLevel1 = Tx_Extbase_Utility_Localization::translate('sections.Rl1', 'indexed_search');
+                       $labelLevel2 = Tx_Extbase_Utility_Localization::translate('sections.Rl2', 'indexed_search');
+                       foreach ($firstLevelMenu as $firstLevelKey => $menuItem) {
+                               if (!$menuItem['nav_hide']) {
+                                       $allOptions['rl1_' . $menuItem['uid']] = trim($labelLevel1 . ' ' . $menuItem['title']);
+
+                                       if ($this->settings['displayLevel2Sections']) {
+                                               $secondLevelMenu = $this->getMenuOfPages($menuItem['uid']);
+                                               foreach ($secondLevelMenu as $secondLevelKey => $menuItemLevel2) {
+                                                       if (!$menuItemLevel2['nav_hide']) {
+                                                               $allOptions['rl2_' . $menuItemLevel2['uid']] = trim($labelLevel2 . ' ' . $menuItemLevel2['title']);
+                                                       } else {
+                                                               unset($secondLevelMenu[$secondLevelKey]);
+                                                       }
+                                               }
+                                               $allOptions['rl2_' . implode(',', array_keys($secondLevelMenu))] = Tx_Extbase_Utility_Localization::translate('sections.Rl2All', 'indexed_search');
+                                       }
+                               } else {
+                                       unset($firstLevelMenu[$firstLevelKey]);
+                               }
+                       }
+                       $allOptions['rl1_' . implode(',', array_keys($firstLevelMenu))] = Tx_Extbase_Utility_Localization::translate('sections.Rl1All', 'indexed_search');
+               }
+
+                       // disable single entries by TypoScript
+               $allOptions = $this->removeOptionsFromOptionList($allOptions, $blindSettings['sections.']);
+               return $allOptions;
+       }
+
+
+       /**
+        * get the values for the "freeIndexUid" selector
+        *
+        * @return array Associative array with options
+        */
+       protected function getAllAvailableIndexConfigurationsOptions() {
+               $allOptions = array(
+                       '-1' => Tx_Extbase_Utility_Localization::translate('indexingConfigurations.-1', 'indexed_search'),
+                       '-2' => Tx_Extbase_Utility_Localization::translate('indexingConfigurations.-2', 'indexed_search'),
+                       '0' => Tx_Extbase_Utility_Localization::translate('indexingConfigurations.0', 'indexed_search')
+               );
+               $blindSettings = $this->settings['blind.'];
+               if (!$blindSettings['indexingConfigurations']) {
+
+                               // add an additional index configuration
+                       if ($this->settings['defaultFreeIndexUidList']) {
+                               $uidList = t3lib_div::intExplode(',', $this->settings['defaultFreeIndexUidList']);
+                               $indexCfgRecords = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                                       'uid,title',
+                                       'index_config',
+                                       'uid IN (' . implode(',', $uidList).  ')'
+                                        . $GLOBALS['TSFE']->cObj->enableFields('index_config'),
+                                       '',
+                                       '',
+                                       '',
+                                       'uid'
+                               );
+
+                               foreach ($uidList as $uidValue) {
+                                       if (is_array($indexCfgRecords[$uidValue])) {
+                                               $allOptions[$uidValue] = $indexCfgRecords[$uidValue]['title'];
+                                       }
+                               }
+                       }
+
+                               // disable single entries by TypoScript
+                       $allOptions = $this->removeOptionsFromOptionList($allOptions, $blindSettings['indexingConfigurations.']);
+               } else {
+                       $allOptions = array();
+               }
+               return $allOptions;
+       }
+
+       /**
+        * get the values for the "section" selector
+        * Here values like "rl1_" and "rl2_" + a rootlevel 1/2 id can be added
+        *  to perform searches in rootlevel 1+2 specifically. The id-values can even
+        *  be commaseparated. Eg. "rl1_1,2" would search for stuff inside pages on
+        *  menu-level 1 which has the uid's 1 and 2.
+        *
+        * @return array Associative array with options
+        */
+       protected function getAllAvailableSortOrderOptions() {
+               $allOptions = array();
+               $sortOrders = array('rank_flag', 'rank_freq', 'rank_first', 'rank_count', 'mtime', 'title', 'crdate');
+               $blindSettings = $this->settings['blind.'];
+               if (!$blindSettings['sortOrder']) {
+                       foreach ($sortOrders as $order) {
+                               $allOptions[$order] = Tx_Extbase_Utility_Localization::translate('sortOrders.' . $order, 'indexed_search');
+                       }
+               }
+
+                       // disable single entries by TypoScript
+               $allOptions = $this->removeOptionsFromOptionList($allOptions, $blindSettings['sortOrder.']);
+               return $allOptions;
+       }
+
+       /**
+        * get the values for the "group" selector
+        *
+        * @return array Associative array with options
+        */
+       protected function getAllAvailableGroupOptions() {
+               $allOptions = array();
+               $blindSettings = $this->settings['blind.'];
+               if (!$blindSettings['groupBy']) {
+                       $allOptions = array(
+                               'sections' => Tx_Extbase_Utility_Localization::translate('groupBy.sections', 'indexed_search'),
+                               'flat' => Tx_Extbase_Utility_Localization::translate('groupBy.flat', 'indexed_search')
+                       );
+               }
+
+                       // disable single entries by TypoScript
+               $allOptions = $this->removeOptionsFromOptionList($allOptions, $blindSettings['groupBy.']);
+               return $allOptions;
+       }
+
+       /**
+        * get the values for the "sortDescending" selector
+        *
+        * @return array Associative array with options
+        */
+       protected function getAllAvailableSortDescendingOptions() {
+               $allOptions = array();
+               $blindSettings = $this->settings['blind.'];
+               if (!$blindSettings['descending']) {
+                       $allOptions = array(
+                               0 => Tx_Extbase_Utility_Localization::translate('sortOrders.descending', 'indexed_search'),
+                               1 => Tx_Extbase_Utility_Localization::translate('sortOrders.ascending', 'indexed_search')
+                       );
+               }
+
+                       // disable single entries by TypoScript
+               $allOptions = $this->removeOptionsFromOptionList($allOptions, $blindSettings['descending.']);
+               return $allOptions;
+       }
+
+       /**
+        * get the values for the "results" selector
+        *
+        * @return array Associative array with options
+        */
+       protected function getAllAvailableNumberOfResultsOptions() {
+               $allOptions = array();
+               $blindSettings = $this->settings['blind.'];
+               if (!$blindSettings['numberOfResults']) {
+                       $allOptions = array(
+                               10 => 10,
+                               25 => 25,
+                               50 => 50,
+                               100 => 100
+                       );
+               }
+
+                       // disable single entries by TypoScript
+               $allOptions = $this->removeOptionsFromOptionList($allOptions, $blindSettings['numberOfResults.']);
+               return $allOptions;
+       }
+
+
+       /**
+        * removes blinding entries from the option list of a selector
+        *
+        * @param array $allOptions associative array containing all options
+        * @param array $blindOptions associative array containing the optionkey as they key and the value = 1 if it should be removed
+        * @return array Options from $allOptions with some options removed
+        */
+       protected function removeOptionsFromOptionList($allOptions, $blindOptions) {
+               if (is_array($blindOptions)) {
+                       foreach ($blindOptions as $key => $val) {
+                               if ($val == 1) {
+                                       unset($allOptions[$key]);
+                               }
+                       }
+               }
+               return $allOptions;
+       }
+
+
+
+       /**
+        * Links the $linkText to page $pageUid
+        *
+        * @param integer $pageUid Page id
+        * @param string $linkText Title String to link
+        * @param array $row Result row
+        * @param array $markUpSwParams Additional parameters for marking up seach words
+        * @return string <A> tag wrapped title string.
+        * @todo make use of the UriBuilder
+        */
+       protected function linkPage($pageUid, $linkText, $row=array(), $markUpSwParams = array()) {
+
+                       // Parameters for link
+               $urlParameters = (array) unserialize($row['cHashParams']);
+
+                       // Add &type and &MP variable:
+               if ($row['data_page_mp']) $urlParameters['MP'] = $row['data_page_mp'];
+               if ($row['sys_language_uid']) $urlParameters['L'] = $row['sys_language_uid'];
+
+                       // markup-GET vars:
+               $urlParameters = array_merge($urlParameters, $markUpSwParams);
+
+                       // This will make sure that the path is retrieved if it hasn't been
+                       // already. Used only for the sake of the domain_record thing.
+               if (!is_array($this->domainRecords[$pageUid])) {
+                       $this->getPathFromPageId($pageUid);
+               }
+
+
+                       // If external domain, then link to that:
+               if (count($this->domainRecords[$pageUid])) {
+                       $scheme = t3lib_div::getIndpEnv('TYPO3_SSL') ? 'https://' : 'http://';
+                       $firstDomain = reset($this->domainRecords[$pageUid]);
+
+                       $additionalParams = '';
+                       if (is_array($urlParameters)) {
+                               if (count($urlParameters)) {
+                                       $additionalParams = t3lib_div::implodeArrayForUrl('', $urlParameters);
+                               }
+                       }
+
+                       $uri = $scheme . $firstDomain . '/index.php?id=' . $pageUid . $additionalParams;
+
+                       if ($target = $this->settings['detectDomainRecords.']['target']) {
+                               $target = ' target="' . $target . '"';
+                       }
+               } else {
+                       $uriBuilder = $this->controllerContext->getUriBuilder();
+                       $uri = $uriBuilder
+                               ->setTargetPageUid($pageUid)
+                               ->setTargetPageType($row['data_page_type'])
+                               ->setUseCacheHash(TRUE)
+                               ->setArguments($urlParameters)
+                               ->build();
+               }
+               return '<a href="' . htmlspecialchars($uri) . '"' . $target . '>' . htmlspecialchars($linkText) . '</a>';
+       }
+
+
+
+       /**
+        * Return the menu of pages used for the selector.
+        *
+        * @param integer $pageUid Page ID for which to return menu
+        * @return array Menu items (for making the section selector box)
+        */
+       protected function getMenuOfPages($pageUid) {
+               if ($this->settings['displayLevelxAllTypes']) {
+                       $menu = array();
+                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+                               'title,uid',
+                               'pages',
+                               'pid=' . intval($pageUid)
+                               . $GLOBALS['TSFE']->cObj->enableFields('pages'),
+                               '',
+                               'sorting'
+                       );
+                       while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
+                               $menu[$row['uid']] = $GLOBALS['TSFE']->sys_page->getPageOverlay($row);
+                       }
+                       $GLOBALS['TYPO3_DB']->sql_free_result($res);
+               } else {
+                       $menu = $GLOBALS['TSFE']->sys_page->getMenu($pageUid);
+               }
+               return $menu;
+       }
+
+
+       /**
+        * Returns the path to the page $id
+        *
+        * @param integer $id Page ID
+        * @param string MP variable content
+        * @return string Path
+        */
+       protected function getPathFromPageId($id, $pathMP = '') {
+               $identStr = $id . '|' . $pathMP;
+
+               if (!isset($this->pathCache[$identStr])) {
+                       $this->requiredFrontendUsergroups[$id] = array();
+                       $this->domainRecords[$id] = array();
+                       $rl = $GLOBALS['TSFE']->sys_page->getRootLine($id, $pathMP);
+                       $path = '';
+                       if (is_array($rl) && count($rl)) {
+                               foreach ($rl as $k => $v) {
+                                               // Check fe_user
+                                       if ($v['fe_group'] && ($v['uid'] == $id || $v['extendToSubpages'])) {
+                                               $this->requiredFrontendUsergroups[$id][] = $v['fe_group'];
+                                       }
+
+                                               // Check sys_domain
+                                       if ($this->settings['detectDomainRcords']) {
+                                               $domainName = $this->getFirstSysDomainRecordForPage($v['uid']);
+                                               if ($domainName) {
+                                                       $this->domainRecords[$id][] = $domainName;
+                                                               // Set path accordingly
+                                                       $path = $domainName . $path;
+                                                       break;
+                                               }
+                                       }
+
+                                               // Stop, if we find that the current id is the current root page.
+                                       if ($v['uid'] == $GLOBALS['TSFE']->config['rootLine'][0]['uid']) {
+                                               break;
+                                       }
+                                       $path = '/' . $v['title'] . $path;
+                               }
+                       }
+
+                       $this->pathCache[$identStr] = $path;
+               }
+
+               return $this->pathCache[$identStr];
+       }
+
+
+       /**
+        * Gets the first sys_domain record for the page, $id
+        *
+        * @param integer $id Page id
+        * @return string Domain name
+        */
+       protected function getFirstSysDomainRecordForPage($id) {
+               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+                       'domainName',
+                       'sys_domain',
+                       'pid=' . intval($id)
+                        . $GLOBALS['TSFE']->cObj->enableFields('sys_domain'),
+                       '',
+                       'sorting'
+               );
+               $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
+               return rtrim($row['domainName'], '/');
+       }
+
+
+       /**
+        * simple function to initialize possible external parsers
+        * feeds the $this->externalParsers array
+        *
+        * @return void
+        */
+       protected function initializeExternalParsers() {
+                       // Initialize external document parsers for icon display and other soft operations
+               if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['external_parsers'])) {
+                       foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['external_parsers'] as $extension => $_objRef) {
+                               $this->externalParsers[$extension] = t3lib_div::getUserObj($_objRef);
+
+                                       // Init parser and if it returns FALSE, unset its entry again
+                               if (!$this->externalParsers[$extension]->softInit($extension)) {
+                                       unset($this->externalParsers[$extension]);
+                               }
+                       }
+               }
+       }
+
+
+       /**
+        * Returns an object reference to the hook object if any
+        *
+        * @param string $functionName Name of the function you want to call / hook key
+        * @return object Hook object, if any. Otherwise NULL.
+        */
+       protected function hookRequest($functionName) {
+                       // Hook: menuConfig_preProcessModMenu
+               if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['pi1_hooks'][$functionName]) {
+                       $hookObj = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['pi1_hooks'][$functionName]);
+                       if (method_exists($hookObj, $functionName)) {
+                               $hookObj->pObj = $this;
+                               return $hookObj;
+                       }
+               }
+               return NULL;
+       }
+
+
+       /**
+        * Returns if an item type is a multipage item type
+        *
+        * @param string $item_type Item type
+        * @return boolean TRUE if multipage capable
+        */
+       protected function multiplePagesType($item_type) {
+               return is_object($this->externalParsers[$item_type]) && $this->externalParsers[$item_type]->isMultiplePageExtension($item_type);
+       }
+
+}
+
+
+if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/indexed_search/Classes/Controller/SearchController.php'])) {
+       include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/indexed_search/Classes/Controller/SearchController.php']);
+}
+
+
+?>
diff --git a/typo3/sysext/indexed_search/Classes/Domain/Repository/IndexSearchRepository.php b/typo3/sysext/indexed_search/Classes/Domain/Repository/IndexSearchRepository.php
new file mode 100644 (file)
index 0000000..6504e12
--- /dev/null
@@ -0,0 +1,912 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2011 Benjamin Mack (benni@typo3.org)
+*
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+/**
+ * Index search abstraction to search through the index
+ *
+ * @author     Kasper Skårhøj <kasperYYYY@typo3.com>
+ * @author     Christian Jul Jensen <christian@typo3.com>
+ * @author     Benjamin Mack <benni@typo3.org>
+ *
+ */
+class Tx_IndexedSearch_Domain_Repository_IndexSearchRepository {
+
+       /**
+        * Indexer object
+        *
+        * @var tx_indexedsearch_indexer
+        */
+       protected $indexerObj;
+
+       protected $externalParsers = array();
+
+       protected $frontendUserGroupList = '';
+
+               // formally known as $this->piVars['sections']
+       protected $sections = NULL;
+
+               // formally known as $this->piVars['type']
+       protected $searchType = NULL;
+
+               // formally known as $this->piVars['lang']
+       protected $languageUid = NULL;
+
+               // formally known as $this->piVars['media']
+       protected $mediaType = NULL;
+
+               // formally known as $this->piVars['sort_order']
+       protected $sortOrder = NULL;
+
+               // formally known as $this->piVars['desc']
+       protected $descendingSortOrderFlag = NULL;
+
+               // formally known as $this->piVars['pointer']
+       protected $resultpagePointer = 0;
+
+               // formally known as $this->piVars['result']
+       protected $numberOfResults = 10;
+
+               // list of all root pages that will be used
+       protected $searchRootPageIdList;
+
+               // formally known as $conf['search.']['searchSkipExtendToSubpagesChecking']
+               // enabled through settings.searchSkipExtendToSubpagesChecking
+       protected $joinPagesForQuery = FALSE;
+
+               // Select clauses for individual words,
+               // will be filled during the search
+       protected $wSelClauses = array();
+
+               // formally known as $conf['search.']['exactCount']
+               // Continue counting and checking of results even if we are sure
+               // they are not displayed in this request. This will slow down your
+               // page rendering, but it allows precise search result counters.
+               // enabled through settings.exactCount
+       protected $useExactCount = FALSE;
+
+               // formally known as $this->conf['show.']['forbiddenRecords']
+               // enabled through settings.displayForbiddenRecords
+       protected $displayForbiddenRecords = FALSE;
+
+               // constants to help where to use wildcards in SQL like queries
+       const WILDCARD_LEFT  = 1;
+       const WILDCARD_RIGHT = 2;
+
+       /**
+        * initialize all options that are necessary for the search
+        *
+        * @param array $settings the extbase plugin settings
+        * @param array $searchData the search data
+        * @param array $externalParsers
+        * @param mixed $searchRootPageIdList
+        * @return void
+        */
+       public function initialize($settings, $searchData, $externalParsers, $searchRootPageIdList) {
+
+                       // Initialize the indexer-class - just to use a few function (for making hashes)
+               $this->indexerObj = t3lib_div::makeInstance('tx_indexedsearch_indexer');
+
+               $this->externalParsers = $externalParsers;
+               $this->searchRootPageIdList = $searchRootPageIdList;
+               $this->frontendUserGroupList = $GLOBALS['TSFE']->gr_list;
+
+                       // Should we use joinPagesForQuery instead of long lists of uids?
+               if ($settings['searchSkipExtendToSubpagesChecking']) {
+                       $this->joinPagesForQuery = 1;
+               }
+
+               if ($settings['exactCount']) {
+                       $this->useExactCount = TRUE;
+               }
+
+               if ($settings['displayForbiddenRecords']) {
+                       $this->displayForbiddenRecords = TRUE;
+               }
+
+               $this->sections = $searchData['sections'];
+               $this->searchType = $searchData['searchType'];
+               $this->languageUid = $searchData['languageUid'];
+               $this->mediaType = (isset($searchData['mediaType']) ? $searchData['mediaType'] : FALSE);
+               $this->sortOrder = $searchData['sortOrder'];
+               $this->descendingSortOrderFlag = $searchData['desc'];
+               $this->resultpagePointer = $searchData['pointer'];
+
+               if (isset($searchData['numberOfResults']) && is_numeric($searchData['numberOfResults'])) {
+                       $this->numberOfResults = intval($searchData['numberOfResults']);
+               }
+       }
+
+
+
+
+       /**
+        * Get search result rows / data from database. Returned as data in array.
+        *
+        * @param array $searchWords Search word array
+        * @param integer $freeIndexUid Pointer to which indexing configuration you want to search in. -1 means no filtering. 0 means only regular indexed content.
+        * @return boolean|array FALSE if no result, otherwise an array with keys for first row, result rows and total number of results found.
+        */
+       public function doSearch($searchWords, $freeIndexUid = -1) {
+
+                       // Getting SQL result pointer:
+               $GLOBALS['TT']->push('Searching result');
+               if ($hookObj = &$this->hookRequest('getResultRows_SQLpointer')) {
+                       $res = $hookObj->getResultRows_SQLpointer($searchWords, $freeIndexUid);
+               } else {
+                       $res = $this->getResultRows_SQLpointer($searchWords, $freeIndexUid);
+               }
+               $GLOBALS['TT']->pull();
+
+                       // Organize and process result:
+               if ($res) {
+
+                               // Total search-result count
+                       $count = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
+
+                               // The pointer is set to the result page that is currently being viewed
+                       $pointer = t3lib_div::intInRange($this->resultpagePointer, 0, floor($count / $this->resultsPerPage));
+
+                               // Initialize result accumulation variables:
+                       $c = 0; // Result pointer: Counts up the position in the current search-result
+                       $grouping_phashes = array();    // Used to filter out duplicates.
+                       $grouping_chashes = array();    // Used to filter out duplicates BASED ON cHash.
+                       $firstRow = array();    // Will hold the first row in result - used to calculate relative hit-ratings.
+                       $resultRows = array();  // Will hold the results rows for display.
+
+                               // Now, traverse result and put the rows to be displayed into an array
+                               // Each row should contain the fields from 'ISEC.*, IP.*' combined
+                               // + artificial fields "show_resume" (boolean) and "result_number" (counter)
+                       while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
+
+                                       // Set first row
+                               if (!$c) {
+                                       $firstRow = $row;
+                               }
+
+                                       // Tells whether we can link directly to a document
+                                       // or not (depends on possible right problems)
+                               $row['show_resume'] = $this->checkResume($row);
+
+                               $phashGr = !in_array($row['phash_grouping'], $grouping_phashes);
+                               $chashGr = !in_array($row['contentHash'] . '.' . $row['data_page_id'], $grouping_chashes);
+
+                               if ($phashGr && $chashGr) {
+                                               // Only if the resume may be shown are we going to filter out duplicates...
+                                       if ($row['show_resume'] || $this->displayForbiddenRecords) {
+
+                                                       // Only on documents which are not multiple pages documents
+                                               if (!$this->multiplePagesType($row['item_type'])) {
+                                                       $grouping_phashes[] = $row['phash_grouping'];
+                                               }
+                                               $grouping_chashes[] = $row['contentHash'] . '.' . $row['data_page_id'];
+
+                                                       // Increase the result pointer
+                                               $c++;
+
+                                                       // All rows for display is put into resultRows[]
+                                               if ($c > $pointer * $this->numberOfResults && $c <= ($pointer * $this->numberOfResults + $this->numberOfResults)) {
+                                                       $row['result_number'] = $c;
+                                                       $resultRows[] = $row;
+                                                               // This may lead to a problem: If the result check is not stopped here, the search will take longer.
+                                                               // However the result counter will not filter out grouped cHashes/pHashes that were not processed yet.
+                                                               // You can change this behavior using the "search.exactCount" property (see above).
+                                                       if (!$this->useExactCount && (($c+1) > ($pointer+1) * $this->numberOfResults)) {
+                                                               break;
+                                                       }
+                                               }
+                                       } else {
+                                                       // Skip this row if the user cannot
+                                                       // view it (missing permission)
+                                               $count--;
+                                       }
+                               } else {
+                                               // For each time a phash_grouping document is found
+                                               // (which is thus not displayed) the search-result count is reduced,
+                                               // so that it matches the number of rows displayed.
+                                       $count--;
+                               }
+                       }
+
+                       return array(
+                               'resultRows' => $resultRows,
+                               'firstRow'   => $firstRow,
+                               'count'      => $count
+                       );
+               } else {
+                               // No results found
+                       return FALSE;
+               }
+       }
+
+       /**
+        * Gets a SQL result pointer to traverse for the search records.
+        *
+        * @param array $searchWords Search words
+        * @param integer $freeIndexUid Pointer to which indexing configuration you want to search in. -1 means no filtering. 0 means only regular indexed content.
+        * @return boolean|pointer
+        */
+       protected function getResultRows_SQLpointer($searchWords, $freeIndexUid = -1) {
+                       // This SEARCHES for the searchwords in $searchWords AND returns a
+                       // COMPLETE list of phash-integers of the matches.
+               $list = $this->getPhashList($searchWords);
+
+                       // Perform SQL Search / collection of result rows array:
+               if ($list) {
+                               // Do the search:
+                       $GLOBALS['TT']->push('execFinalQuery');
+                       $res = $this->execFinalQuery($list, $freeIndexUid);
+                       $GLOBALS['TT']->pull();
+                       return $res;
+               } else {
+                       return FALSE;
+               }
+       }
+
+
+
+
+       /***********************************
+        *
+        *      Helper functions on searching (SQL)
+        *
+        ***********************************/
+
+       /**
+        * Returns a COMPLETE list of phash-integers matching the search-result composed of the search-words in the $searchWords array.
+        * The list of phash integers are unsorted and should be used for subsequent selection of index_phash records for display of the result.
+        *
+        * @param array $searchWords Search word array
+        * @return string List of integers
+        */
+       protected function getPhashList($searchWords) {
+
+                       // Initialize variables:
+               $c = 0;
+                       // This array accumulates the phash-values
+               $totalHashList = array();
+
+                       // Traverse searchwords; for each, select all phash integers and merge/diff/intersect them with previous word (based on operator)
+               foreach ($searchWords as $k => $v) {
+                               // Making the query for a single search word based on the search-type
+                       $sWord = $v['sword'];   // $GLOBALS['TSFE']->csConvObj->conv_case('utf-8',$v['sword'],'toLower');       // lower-case all of them...
+                       $theType = (string) $this->searchType;
+                               // If there are spaces in the search-word, make a full text search instead.
+                       if (strstr($sWord,' ')) {
+                               $theType = 20;
+                       }
+
+                       $GLOBALS['TT']->push('SearchWord "' . $sWord . '" - $theType=' . $theType);
+
+                       $res = '';
+                       $wSel = '';
+
+                               // Perform search for word:
+                       switch ($theType) {
+                               case '1':
+                                               // Part of word
+                                       $res = $this->searchWord($sWord, self::WILDCARD_LEFT | self::WILDCARD_RIGHT);
+                               break;
+                               case '2':
+                                               // First part of word
+                                       $res = $this->searchWord($sWord, self::WILDCARD_RIGHT);
+                               break;
+                               case '3':
+                                               // Last part of word
+                                       $res = $this->searchWord($sWord, self::WILDCARD_LEFT);
+                               break;
+                               case '10':
+                                               // Sounds like
+
+                                       /**
+                                        * Indexer object
+                                        *
+                                        * @var tx_indexedsearch_indexer
+                                        */
+                                       $indexerObj = t3lib_div::makeInstance('tx_indexedsearch_indexer');
+
+                                               // Perform metaphone search
+                                       $storeMetaphoneInfoAsWords = $this->isTableUsed('index_words') ? FALSE : TRUE;
+                                       $res = $this->searchMetaphone($indexerObj->metaphone($sWord, $storeMetaphoneInfoAsWords));
+                                       unset($indexerObj);
+                               break;
+                               case '20':
+                                               // Sentence
+                                       $res = $this->searchSentence($sWord);
+
+                                               // If there is a fulltext search for a sentence there is
+                                               // a likeliness that sorting cannot be done by the rankings
+                                               // from the rel-table (because no relations will exist for the
+                                               // sentence in the word-table). So therefore mtime is used instead.
+                                               // It is not required, but otherwise some hits may be left out.
+                                       $this->sortOrder = 'mtime';
+                               break;
+                               default:
+                                               // Distinct word
+                                       $res = $this->searchDistinct($sWord);
+                               break;
+                       }
+
+                               // Accumulate the word-select clauses
+                       $this->wSelClauses[] = $wSel;
+
+                               // If there was a query to do, then select all phash-integers which resulted from this.
+                       if ($res) {
+
+                                       // Get phash list by searching for it:
+                               $phashList = array();
+                               while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
+                                       $phashList[] = $row['phash'];
+                               }
+                               $GLOBALS['TYPO3_DB']->sql_free_result($res);
+
+                                       // Here the phash list are merged with the existing result based on whether we are dealing with OR, NOT or AND operations.
+                               if ($c) {
+                                       switch($v['oper']) {
+                                               case 'OR':
+                                                       $totalHashList = array_unique(array_merge($phashList, $totalHashList));
+                                               break;
+                                               case 'AND NOT':
+                                                       $totalHashList = array_diff($totalHashList, $phashList);
+                                               break;
+                                               default:
+                                                       // AND...
+                                                       $totalHashList = array_intersect($totalHashList, $phashList);
+                                               break;
+                                       }
+                               } else {
+                                               // First search
+                                       $totalHashList = $phashList;
+                               }
+                       }
+
+                       $GLOBALS['TT']->pull();
+                       $c++;
+               }
+
+               return implode(',', $totalHashList);
+       }
+
+       /**
+        * Returns a query which selects the search-word from the word/rel tables.
+        *
+        * @param       string          WHERE clause selecting the word from phash
+        * @param       string          Additional AND clause in the end of the query.
+        * @return      pointer         SQL result pointer
+        */
+       protected function execPHashListQuery($wordSel, $additionalWhereClause = '') {
+               return $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+                                       'IR.phash',
+                                       'index_words IW,
+                                               index_rel IR,
+                                               index_section ISEC',
+                                       $wordSel . '
+                                               AND IW.wid=IR.wid
+                                               AND ISEC.phash=IR.phash
+                                               ' . $this->sectionTableWhere() . '
+                                               ' . $additionalWhereClause,
+                                       'IR.phash'
+                               );
+       }
+
+       /**
+        * Search for a word
+        *
+        * @param       string the search word
+        * @param       integer constant from this class to see if the wildcard should be left and/or right of the search string
+        * @return      pointer         SQL result pointer
+        */
+       protected function searchWord($sWord, $mode) {
+               $wildcard_left = ($mode & WILDCARD_LEFT) ? '%' : '';
+               $wildcard_right = ($mode & WILDCARD_RIGHT) ? '%' : '';
+
+               $wSel = 'IW.baseword LIKE \'' . $wildcard_left . $GLOBALS['TYPO3_DB']->quoteStr($sWord, 'index_words') . $wildcard_right . '\'';
+               $res = $this->execPHashListQuery($wSel,' AND is_stopword=0');
+               return $res;
+       }
+
+       /**
+        * Search for one distinct word
+        *
+        * @param       string the search word
+        * @return      pointer         SQL result pointer
+        */
+       protected function searchDistinct($sWord) {
+               $wSel = 'IW.wid=' . $this->md5inthash($sWord);
+               $res = $this->execPHashListQuery($wSel, ' AND is_stopword=0');
+               return $res;
+       }
+
+       /**
+        * Search for a sentence
+        *
+        * @param       string the search word
+        * @return      pointer         SQL result pointer
+        */
+       protected function searchSentence($sWord) {
+               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+                                       'ISEC.phash',
+                                       'index_section ISEC, index_fulltext IFT',
+                                       'IFT.fulltextdata LIKE \'%' . $GLOBALS['TYPO3_DB']->quoteStr($sWord, 'index_fulltext') . '%\' AND
+                                               ISEC.phash = IFT.phash
+                                               ' . $this->sectionTableWhere(),
+                                       'ISEC.phash'
+                               );
+               return $res;
+       }
+
+       /**
+        * Search for a metaphone word
+        *
+        * @param       string the search word
+        * @return      pointer         SQL result pointer
+        */
+       protected function searchMetaphone($sWord) {
+               $wSel = 'IW.metaphone=' . $sWord;
+               $res = $this->execPHashListQuery($wSel, ' AND is_stopword=0');
+       }
+
+       /**
+        * Returns AND statement for selection of section in database. (rootlevel 0-2 + page_id)
+        *
+        * @return      string          AND clause for selection of section in database.
+        */
+       protected function sectionTableWhere() {
+               $whereClause = '';
+               $match = FALSE;
+
+               if (!($this->searchRootPageIdList < 0)) {
+                       $whereClause = ' AND ISEC.rl0 IN (' . $this->searchRootPageIdList . ') ';
+               }
+
+               if (substr($this->sections, 0, 4) == 'rl1_') {
+                       $list = implode(',', t3lib_div::intExplode(',', substr($this->sections, 4)));
+                       $whereClause .= ' AND ISEC.rl1 IN (' . $list . ')';
+                       $match = TRUE;
+               } elseif (substr($this->sections, 0, 4) == 'rl2_') {
+                       $list = implode(',', t3lib_div::intExplode(',', substr($this->sections, 4)));
+                       $whereClause .= ' AND ISEC.rl2 IN (' . $list . ')';
+                       $match = TRUE;
+               } elseif (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['addRootLineFields'])) {
+                               // Traversing user configured fields to see if any of those are used to limit search to a section:
+                       foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['addRootLineFields'] as $fieldName => $rootLineLevel) {
+                               if (substr($this->sections, 0, strlen($fieldName)+1) == $fieldName . '_') {
+                                       $list = implode(',', t3lib_div::intExplode(',', substr($this->sections, strlen($fieldName) + 1)));
+                                       $whereClause .= ' AND ISEC.' . $fieldName . ' IN (' . $list . ')';
+                                       $match = TRUE;
+                                       break;
+                               }
+                       }
+               }
+
+                       // If no match above, test the static types:
+               if (!$match) {
+                       switch((string) $this->sections) {
+                                       // '-1' => 'Only this page',
+                               case '-1':
+                                       $whereClause.= ' AND ISEC.page_id=' . $GLOBALS['TSFE']->id;
+                               break;
+                                       // '-2' => 'Top + level 1',
+                               case '-2':
+                                       $whereClause.= ' AND ISEC.rl2=0';
+                               break;
+                                       // '-3' => 'Level 2 and out',
+                               case '-3':
+                                       $whereClause.= ' AND ISEC.rl2>0';
+                               break;
+                       }
+               }
+               return $whereClause;
+       }
+
+
+       /**
+        * Returns AND statement for selection of media type
+        *
+        * @return      string          AND statement for selection of media type
+        */
+       public function mediaTypeWhere() {
+               $whereClause = '';
+
+               switch ($this->mediaType) {
+                       case '0':       // '0' => 'Kun TYPO3 sider',
+                               $whereClause = ' AND IP.item_type=' . $GLOBALS['TYPO3_DB']->fullQuoteStr('0', 'index_phash');
+                       break;
+                       case '-2':      // All external documents
+                               $whereClause = ' AND IP.item_type!=' . $GLOBALS['TYPO3_DB']->fullQuoteStr('0', 'index_phash');
+                       break;
+                       case FALSE:
+                       case '-1':      // All content
+                               $whereClause = '';
+                       break;
+                       default:
+                               $whereClause = ' AND IP.item_type=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->mediaType, 'index_phash');
+                       break;
+               }
+
+               return $whereClause;
+       }
+
+       /**
+        * Returns AND statement for selection of langauge
+        *
+        * @return      string          AND statement for selection of langauge
+        */
+       public function languageWhere() {
+                       // -1 is the same as ALL language.
+               if ($this->languageUid >= 0) {
+                       return ' AND IP.sys_language_uid=' . intval($this->languageUid);
+               }
+       }
+
+       /**
+        * Where-clause for free index-uid value.
+        *
+        * @param       integer         Free Index UID value to limit search to.
+        * @return      string          WHERE SQL clause part.
+        */
+       public function freeIndexUidWhere($freeIndexUid) {
+
+               if ($freeIndexUid >= 0) {
+
+                               // First, look if the freeIndexUid is a meta configuration:
+                       $indexCfgRec = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
+                               'indexcfgs',
+                               'index_config',
+                               'type=5 AND uid=' . intval($freeIndexUid) . $this->enableFields('index_config')
+                       );
+                       if (is_array($indexCfgRec)) {
+                               $refs = t3lib_div::trimExplode(',', $indexCfgRec['indexcfgs']);
+                                       // Default value to protect against empty array.
+                               $list = array(-99);
+                               foreach ($refs as $ref) {
+                                       list($table, $uid) = t3lib_div::revExplode('_', $ref, 2);
+                                       switch ($table) {
+                                               case 'index_config':
+                                                       $idxRec = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
+                                                               'uid',
+                                                               'index_config',
+                                                               'uid=' . intval($uid) . $this->enableFields('index_config')
+                                                       );
+                                                       if ($idxRec) {
+                                                               $list[] = $uid;
+                                                       }
+                                               break;
+                                               case 'pages':
+                                                       $indexCfgRecordsFromPid = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                                                               'uid',
+                                                               'index_config',
+                                                               'pid=' . intval($uid) . $this->enableFields('index_config')
+                                                       );
+                                                       foreach ($indexCfgRecordsFromPid as $idxRec) {
+                                                               $list[] = $idxRec['uid'];
+                                                       }
+                                               break;
+                                       }
+                               }
+                               $list = array_unique($list);
+                       } else {
+                               $list = array(intval($freeIndexUid));
+                       }
+                       return ' AND IP.freeIndexUid IN (' . implode(',', $list) . ')';
+               }
+       }
+
+       /**
+        * Execute final query, based on phash integer list. The main point is sorting the result in the right order.
+        *
+        * @param       string          List of phash integers which match the search.
+        * @param       integer         Pointer to which indexing configuration you want to search in. -1 means no filtering. 0 means only regular indexed content.
+        * @return      pointer         Query result pointer
+        */
+       protected function execFinalQuery($list, $freeIndexUid = -1) {
+
+                       // Setting up methods of filtering results
+                       // based on page types, access, etc.
+               $page_join = '';
+               $page_where = '';
+
+                       // Indexing configuration clause:
+               $freeIndexUidClause = $this->freeIndexUidWhere($freeIndexUid);
+
+                       // Calling hook for alternative creation of page ID list
+               if ($hookObj = $this->hookRequest('execFinalQuery_idList')) {
+                       $page_where = $hookObj->execFinalQuery_idList($list);
+               }
+                       // Alternative to getting all page ids by ->getTreeList() where
+                       // "excludeSubpages" is NOT respected.
+               if ($this->joinPagesForQuery) {
+                       $page_join = ',
+                               pages';
+                       $page_where = ' AND pages.uid = ISEC.page_id
+                               ' . $this->enableFields('pages').'
+                               AND pages.no_search=0
+                               AND pages.doktype<200
+                       ';
+               } elseif ($this->searchRootPageIdList >= 0) {
+                               // Collecting all pages IDs in which to search;
+                               // filtering out ALL pages that are not accessible due to enableFields.
+                               // Does NOT look for "no_search" field!
+                       $siteIdNumbers = t3lib_div::intExplode(',', $this->searchRootPageIdList);
+                       $pageIdList = array();
+                       foreach ($siteIdNumbers as $rootId) {
+                               $pageIdList[] = tslib_cObj::getTreeList($rootId, 9999, 0, 0, '', '') . $rootId;
+                       }
+                       $page_where = ' AND ISEC.page_id IN (' . implode(',', $pageIdList) . ')';
+               }
+                       // otherwise select all / disable everything
+
+                       // If any of the ranking sortings are selected, we must make a 
+                       // join with the word/rel-table again, because we need to
+                       // calculate ranking based on all search-words found.
+               if (substr($this->sortOrder, 0, 5) == 'rank_') {
+
+                       switch ($this->sortOrder) {
+                               case 'rank_flag':
+                                               // This gives priority to word-position (max-value) so that words in title, keywords, description counts more than in content.
+                                               // The ordering is refined with the frequency sum as well.
+                                       $grsel = 'MAX(IR.flags) AS order_val1, SUM(IR.freq) AS order_val2';
+                                       $orderBy = 'order_val1' . $this->getDescendingSortOrderFlag().', order_val2' . $this->getDescendingSortOrderFlag();
+                               break;
+                               case 'rank_first':
+                                               // Results in average position of search words on page.
+                                               // Must be inversely sorted (low numbers are closer to top)
+                                       $grsel = 'AVG(IR.first) AS order_val';
+                                       $orderBy = 'order_val' . $this->getDescendingSortOrderFlag(TRUE);
+                               break;
+                               case 'rank_count':
+                                               // Number of words found
+                                       $grsel = 'SUM(IR.count) AS order_val';
+                                       $orderBy = 'order_val' . $this->getDescendingSortOrderFlag();
+                               break;
+                               default:
+                                               // Frequency sum. I'm not sure if this is the best way to do
+                                               // it (make a sum...). Or should it be the average?
+                                       $grsel = 'SUM(IR.freq) AS order_val';
+                                       $orderBy = 'order_val' . $this->getDescendingSortOrderFlag();
+                               break;
+                       }
+
+                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+                                               'ISEC.*, IP.*, '
+                                                . $grsel,
+                                               'index_words IW,
+                                                       index_rel IR,
+                                                       index_section ISEC,
+                                                       index_phash IP' .
+                                                       $page_join,
+                                                       'IP.phash IN (' . $list . ') '.
+                                                       $this->mediaTypeWhere() .
+                                                       $this->languageWhere() .
+                                                       $freeIndexUidClause.'
+                                                       AND IW.wid=IR.wid
+                                                       AND ISEC.phash = IR.phash
+                                                       AND IP.phash = IR.phash' .
+                                                       $page_where,
+                                               'IP.phash,ISEC.phash,ISEC.phash_t3,ISEC.rl0,ISEC.rl1,ISEC.rl2 ,ISEC.page_id,ISEC.uniqid,IP.phash_grouping,IP.data_filename ,IP.data_page_id ,IP.data_page_reg1,IP.data_page_type,IP.data_page_mp,IP.gr_list,IP.item_type,IP.item_title,IP.item_description,IP.item_mtime,IP.tstamp,IP.item_size,IP.contentHash,IP.crdate,IP.parsetime,IP.sys_language_uid,IP.item_crdate,IP.cHashParams,IP.externalUrl,IP.recordUid,IP.freeIndexUid,IP.freeIndexSetId',
+                                               $orderBy
+                                       );
+               } else {
+
+                               // Otherwise, if sorting are done with the pages table or other fields, 
+                               // there is no need for joining with the rel/word tables:
+                       $orderBy = '';
+                       switch((string) $this->sortOrder) {
+                               case 'title':
+                                       $orderBy = 'IP.item_title' . $this->getDescendingSortOrderFlag();
+                               break;
+                               case 'crdate':
+                                       $orderBy = 'IP.item_crdate' . $this->getDescendingSortOrderFlag();
+                               break;
+                               case 'mtime':
+                                       $orderBy = 'IP.item_mtime' . $this->getDescendingSortOrderFlag();
+                               break;
+                       }
+
+                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+                                               'ISEC.*, IP.*',
+                                               'index_phash IP,index_section ISEC' . $page_join,
+                                               'IP.phash IN (' . $list . ') ' .
+                                                       $this->mediaTypeWhere() .
+                                                       $this->languageWhere() .
+                                                       $freeIndexUidClause . '
+                                                       AND IP.phash = ISEC.phash'
+                                                       . $page_where,
+                                               'IP.phash,ISEC.phash,ISEC.phash_t3,ISEC.rl0,ISEC.rl1,ISEC.rl2 ,ISEC.page_id,ISEC.uniqid,IP.phash_grouping,IP.data_filename ,IP.data_page_id ,IP.data_page_reg1,IP.data_page_type,IP.data_page_mp,IP.gr_list,IP.item_type,IP.item_title,IP.item_description,IP.item_mtime,IP.tstamp,IP.item_size,IP.contentHash,IP.crdate,IP.parsetime,IP.sys_language_uid,IP.item_crdate,IP.cHashParams,IP.externalUrl,IP.recordUid,IP.freeIndexUid,IP.freeIndexSetId',
+                                               $orderBy
+                                       );
+               }
+               return $res;
+       }
+
+       /**
+        * Checking if the resume can be shown for the search result
+        * (depending on whether the rights are OK)
+        * ? Should it also check for gr_list "0,-1"?
+        *
+        * @param array $row Result row array.
+        * @return boolean Returns TRUE if resume can safely be shown
+        */
+       protected function checkResume($row) {
+
+                       // If the record is indexed by an indexing configuration, just show it.
+                       // At least this is needed for external URLs and files.
+                       // For records we might need to extend this - for instance block display if record is access restricted.
+               if ($row['freeIndexUid']) {
+                       return TRUE;
+               }
+
+                       // Evaluate regularly indexed pages based on item_type:
+
+                       // External media:
+               if ($row['item_type']) {
+                               // For external media we will check the access of the parent page on which the media was linked from.
+                               // "phash_t3" is the phash of the parent TYPO3 page row which initiated the indexing of the documents in this section.
+                               // So, selecting for the grlist records belonging to the parent phash-row where the current users gr_list exists will help us to know.
+                               // If this is NOT found, there is still a theoretical possibility that another user accessible page would display a link, so maybe the resume of such a document here may be unjustified hidden. But better safe than sorry.
+                       if ($this->isTableUsed('index_grlist')) {
+                               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+                                       'phash',
+                                       'index_grlist',
+                                       'phash=' . intval($row['phash_t3']) . ' AND gr_list=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->frontendUserGroupList, 'index_grlist')
+                               );
+                       } else {
+                               $res = FALSE;
+                       }
+                       if ($res && $GLOBALS['TYPO3_DB']->sql_num_rows($res)) {
+                               #debug("Look up for external media '".$row['data_filename']."': phash:".$row['phash_t3'].' YES - ('.$this->frontendUserGroupList.")!");
+                               return TRUE;
+                       } else {
+                               #debug("Look up for external media '".$row['data_filename']."': phash:".$row['phash_t3'].' NO - ('.$this->frontendUserGroupList.")!");
+                               return FALSE;
+                       }
+               } else {
+                       // Ordinary TYPO3 pages:
+                       if (strcmp($row['gr_list'], $this->frontendUserGroupList)) {
+                                       // Selecting for the grlist records belonging to the phash-row where the current users gr_list exists. If it is found it is proof that this user has direct access to the phash-rows content although he did not himself initiate the indexing...
+                               if ($this->isTableUsed('index_grlist')) {
+                                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+                                               'phash',
+                                               'index_grlist',
+                                               'phash=' . intval($row['phash']) . ' AND gr_list=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->frontendUserGroupList, 'index_grlist')
+                                       );
+                               } else {
+                                       $res = FALSE;
+                               }
+                               if ($res && $GLOBALS['TYPO3_DB']->sql_num_rows($res)) {
+                                       #debug('Checking on it ...'.$row['item_title'].'/'.$row['phash'].' - YES ('.$this->frontendUserGroupList.")");
+                                       return TRUE;
+                               } else {
+                                       #debug('Checking on it ...'.$row['item_title'].'/'.$row['phash']." - NOPE");
+                                       return FALSE;
+                               }
+                       } else {
+                                       #debug('Resume can be shown, because the document was in fact indexed by this combination of groups!'.$this->frontendUserGroupList.' - '.$row['item_title'].'/'.$row['phash']);
+                               return TRUE;
+                       }
+               }
+       }
+
+       /**
+        * Returns "DESC" or "" depending on the settings of the incoming
+        * highest/lowest result order (piVars['desc'])
+        *
+        * @param boolean $inverse If TRUE, inverse the order which is defined by piVars['desc']
+        * @return string " DESC" or ""
+        * @formallyknownas "tx_indexedsearch_pi->isDescending"
+        */
+       protected function getDescendingSortOrderFlag($inverse = FALSE) {
+               $desc = $this->descendingSortOrderFlag;
+               if ($inverse) {
+                       $desc = !$desc;
+               }
+               return (!$desc ? ' DESC' : '');
+       }
+
+       /**
+        * Returns a part of a WHERE clause which will filter out records with start/end times or hidden/fe_groups fields
+        * set to values that should de-select them according to the current time, preview settings or user login.
+        * Definitely a frontend function.
+        * THIS IS A VERY IMPORTANT FUNCTION: Basically you must add the output from this function for EVERY select query you create
+        * for selecting records of tables in your own applications - thus they will always be filtered according to the "enablefields"
+        * configured in TCA
+        * Simply calls t3lib_pageSelect::enableFields() BUT will send the show_hidden flag along!
+        * This means this function will work in conjunction with the preview facilities of the frontend engine/Admin Panel.
+        *
+        * @param       string          The table for which to get the where clause
+        * @param       boolean         If set, then you want NOT to filter out hidden records. Otherwise hidden record are filtered based on the current preview settings.
+        * @return      string          The part of the where clause on the form " AND [fieldname]=0 AND ...". Eg. " AND hidden=0 AND starttime < 123345567"
+        * @see t3lib_pageSelect::enableFields()
+        */
+       protected function enableFields($table) {
+               return $GLOBALS['TSFE']->sys_page->enableFields(
+                       $table,
+                       ($table == 'pages' ? $GLOBALS['TSFE']->showHiddenPage : $GLOBALS['TSFE']->showHiddenRecords)
+               );
+       }
+
+
+       /**
+        * Returns if an item type is a multipage item type
+        *
+        * @param       string          Item type
+        * @return      boolean         TRUE if multipage capable
+        */
+       protected function multiplePagesType($itemType) {
+               return is_object($this->externalParsers[$itemType]) && $this->externalParsers[$itemType]->isMultiplePageExtension($itemType);
+       }
+
+       /**
+        * md5 integer hash
+        * Using 7 instead of 8 just because that makes the integers lower than
+        * 32 bit (28 bit) and so they do not interfere with UNSIGNED integers
+        * or PHP-versions which has varying output from the hexdec function.
+        *
+        * @param string $str String to hash
+        * @return integer Integer intepretation of the md5 hash of input string.
+        */
+       protected function md5inthash($str) {
+               return tx_indexedsearch_indexer::md5inthash($str);
+       }
+
+       /**
+        * Check if the tables provided are configured for usage.
+        * This becomes neccessary for extensions that provide additional database
+        * functionality like indexed_search_mysql.
+        *
+        * @param string $table_list Comma-separated list of tables
+        * @return boolean TRUE if given tables are enabled
+        */
+       protected function isTableUsed($table_list) {
+               return tx_indexedsearch_indexer::isTableUsed($table_list);
+       }
+
+       /**
+        * Returns an object reference to the hook object if any
+        *
+        * @param string $functionName Name of the function you want to call / hook key
+        * @return object Hook object, if any. Otherwise NULL.
+        */
+       public function hookRequest($functionName) {
+
+                       // Hook: menuConfig_preProcessModMenu
+               if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['pi1_hooks'][$functionName]) {
+                       $hookObj = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['pi1_hooks'][$functionName]);
+                       if (method_exists($hookObj, $functionName)) {
+                               $hookObj->pObj = $this;
+                               return $hookObj;
+                       }
+               }
+       }
+}
+
+
+if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/indexed_search/Classes/Repository/IndexSearchRepository.php'])) {
+       include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/indexed_search/Classes/Repository/IndexSearchRepository.php']);
+}
+
+
+?>
diff --git a/typo3/sysext/indexed_search/Classes/ViewHelpers/PageBrowsingResultsViewHelper.php b/typo3/sysext/indexed_search/Classes/ViewHelpers/PageBrowsingResultsViewHelper.php
new file mode 100644 (file)
index 0000000..22c8003
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2011 Benjamin Mack (benni@typo3.org)
+*
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+/**
+ * renders the header of the results page
+ *
+ * @author     Benjamin Mack <benni@typo3.org>
+ *
+ */
+class Tx_IndexedSearch_ViewHelpers_PageBrowsingResultsViewHelper extends Tx_Fluid_Core_ViewHelper_AbstractViewHelper {
+
+
+       /**
+        * main render function
+        * 
+        * @param integer $numberOfResults
+        * @param integer $resultsPerPage
+        * @param integer $currentPage
+        * @return the content
+        */
+       public function render($numberOfResults, $resultsPerPage, $currentPage = 1) {
+
+               $firstResultOnPage = $currentPage * $resultsPerPage + 1;
+               $lastResultOnPage = $currentPage * $resultsPerPage + $resultsPerPage;
+               $label = Tx_Extbase_Utility_Localization::translate('displayResults', 'indexed_search');
+
+               $content = sprintf(
+                       $label,
+                       $firstResultOnPage,
+                       min(array($numberOfResults, $lastResultOnPage)),
+                       $numberOfResults
+               );
+
+               return $content;
+       }
+
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/indexed_search/Classes/ViewHelpers/PageBrowsingViewHelper.php b/typo3/sysext/indexed_search/Classes/ViewHelpers/PageBrowsingViewHelper.php
new file mode 100644 (file)
index 0000000..8633305
--- /dev/null
@@ -0,0 +1,120 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2011 Benjamin Mack (benni@typo3.org)
+*
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+/**
+ * Page browser for indexed search, and only useful here, as the 
+ * regular pagebrowser 
+ * so this is a cleaner "pi_browsebox" but not a real page browser
+ * functionality
+ *
+ * @author     Benjamin Mack <benni@typo3.org>
+ *
+ */
+class Tx_IndexedSearch_ViewHelpers_PageBrowsingViewHelper extends Tx_Fluid_Core_ViewHelper_AbstractViewHelper {
+
+
+       /**
+        * main render function
+        * 
+        * @param array $details        an array with the browser settings
+        * @param integer $maximumNumberOfResultPages
+        * @param integer $numberOfResults
+        * @param integer $resultsPerPage
+        * @param integer $currentPage
+        * @return the content
+        */
+       public function render($maximumNumberOfResultPages, $numberOfResults, $resultsPerPage, $currentPage = 1) {
+               $maximumNumberOfResultPages = t3lib_div::intInRange($maximumNumberOfResultPages, 1, 100, 10);
+
+               $pageCount = ceil($numberOfResults / $resultsPerPage);
+
+               $content = '';
+
+                       // only show the result browser if more than one page is needed
+               if ($pageCount > 1) {
+                       $currentPage = intval($currentPage);
+                               
+                               // prev page
+                               // show on all pages after the 1st one
+                       if ($currentPage > 0) {
+                               $label = Tx_Extbase_Utility_Localization::translate('displayResults.previous', 'indexed_search');
+                               $content .= '<li>' . $this->makecurrentPageSelector_link($label, $currentPage-1, $freeIndexUid) . '</li>';
+                       }
+
+                       for ($a = 0; $a < $pageCount; $a++) {
+                               $min = max(0, $currentPage + 1 - ceil($maximumNumberOfResultPages / 2));
+                               $max = $min + $maximumNumberOfResultPages;
+                               if ($max > $pageCount) {
+                                       $min = $min - ($max-$pageCount);
+                               }
+
+                               if ($a >= $min && $a < $max) {
+                                       $label = Tx_Extbase_Utility_Localization::translate('displayResults.page', 'indexed_search');
+                                       $label = trim($label . ' '  . ($a + 1));
+                                       $label = $this->makecurrentPageSelector_link($label, $a, $freeIndexUid);
+                                       if ($a == $currentPage) {
+                                               $content .= '<li class="tx-indexedsearch-browselist-currentPage"><strong>' . $label . '</strong></li>';
+                                       } else {
+                                               $content .= '<li>' . $label . '</li>';
+                                       }
+                               }
+                       }
+
+                               // next link
+                       if ($currentPage+1 < $pageCount) {
+                               $label = Tx_Extbase_Utility_Localization::translate('displayResults.next', 'indexed_search');
+                               $content = '<li>' . $this->makecurrentPageSelector_link($label, $currentPage + 1, $freeIndexUid) . '</li>';
+                       }
+
+                       $content = '<ul class="tx-indexedsearch-browsebox">' . $content . '</ul>';
+               }
+
+               return $content;
+       }
+
+
+
+
+       /**
+        * Used to make the link for the result-browser.
+        * Notice how the links must resubmit the form after setting the new currentPage-value in a hidden formfield.
+        *
+        * @param string $str String to wrap in <a> tag
+        * @param integer $p currentPage value
+        * @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!
+        * @return string Input string wrapped in <a> tag with onclick event attribute set.
+        */
+       function makecurrentPageSelector_link($str, $p, $freeIndexUid) {
+               $onclick = 'document.getElementById(\'' . $this->prefixId . '_currentPage\').value=\'' . $p . '\';' .
+                                       'document.getElementById(\'' . $this->prefixId . '_freeIndexUid\').value=\'' . rawurlencode($freeIndexUid) . '\';' .
+                                       'document.getElementById(\'' . $this->prefixId . '\').submit();return false;';
+               return '<a href="#" onclick="' . htmlspecialchars($onclick) . '">'.$str . '</a>';
+       }
+
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/indexed_search/Configuration/TypoScript/constants.txt b/typo3/sysext/indexed_search/Configuration/TypoScript/constants.txt
new file mode 100644 (file)
index 0000000..75ed86d
--- /dev/null
@@ -0,0 +1,10 @@
+plugin.tx_indexedsearch {
+       view {
+                # cat=plugin.tx_indexedsearch/file; type=string; label=Path to template root (FE)
+               templateRootPath = EXT:indexedsearch/Resources/Private/Templates/
+                # cat=plugin.tx_indexedsearch/file; type=string; label=Path to template partials (FE)
+               partialRootPath = EXT:indexedsearch/Resources/Private/Partials/
+                # cat=plugin.tx_indexedsearch/file; type=string; label=Path to template layouts (FE)
+               layoutRootPath = EXT:indexedsearch/Resources/Private/Layouts/
+       }
+}
\ No newline at end of file
diff --git a/typo3/sysext/indexed_search/Configuration/TypoScript/setup.txt b/typo3/sysext/indexed_search/Configuration/TypoScript/setup.txt
new file mode 100644 (file)
index 0000000..751a3f3
--- /dev/null
@@ -0,0 +1,92 @@
+config.index_enable = 0
+config.index_externals = 0
+config.index_metatags = 1
+
+ # Plugin configuration
+plugin.tx_indexedsearch {
+
+       settings {
+
+               # show the rules
+               displayRules = 1
+
+               # show a link to the advanced search
+               displayAdvancedSearchLink = 1
+
+               # show the number of results
+               displayResultNumber = 0
+
+               # show the parse times
+               displayParsetimes = 0
+               displayLevel1Sections = 1
+               displayLevel2Sections = 0
+               displayLevelxAllTypes = 0
+               clearSearchBox = 0
+               clearSearchBox.enableSubSearchCheckBox = 1
+               displayForbiddenRecords = 0
+               alwaysShowPageLinks = 1
+               mediaList =
+
+               #search.rootPidList
+               rootPidList =
+               page_links = 10
+               detectDomainRcords = 0
+               defaultFreeIndexUidList =
+               searchSkipExtendToSubpagesChecking = 0
+               exactCount = 0
+               forwardSearchWordsInResultLink = 0
+
+               # Blinding of option-selectors / values in these (advanced search)
+               blind {
+                       searchType = 0
+                       defaultOperand = 0
+                       sections = 0
+                       freeIndexUid = 1
+                       mediaType = 0
+                       sortOrder = 0
+                       group = 0
+                       languageUid = 0
+                       desc = 0
+                       results = 0
+                       # defaultOperand.1 = 1
+                       # extResume=1
+               }
+/*
+               flagRendering = CASE
+               flagRendering {
+                       key.current = 1
+                       2 = TEXT
+                       2.value = German
+                       default = TEXT
+                       default.value = English
+               }
+
+               iconRendering = CASE
+               iconRendering {
+                       key.current = 1
+                       html = TEXT
+                       html.value = HtmL
+                       default = TEXT
+                       default.value = TYPO3 pages
+               }
+*/
+               defaultOptions {
+                       defaultOperand = 0
+                       sections = 0
+                       freeIndexUid = -1
+                       mediaType = -1
+                       sortOrder = rank_flag
+                       languageUid = -1
+                       sortDesc = 1
+               }
+
+       }
+
+
+       view {
+               templateRootPath = {$plugin.tx_indexedsearch.view.templateRootPath}
+               partialRootPath = {$plugin.tx_indexedsearch.view.partialRootPath}
+               layoutRootPath = {$plugin.tx_indexedsearch.view.layoutRootPath}
+       }
+
+}
diff --git a/typo3/sysext/indexed_search/Resources/Private/Language/locallang.xml b/typo3/sysext/indexed_search/Resources/Private/Language/locallang.xml
new file mode 100755 (executable)
index 0000000..acea743
--- /dev/null
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<T3locallang>
+       <meta type="array">
+               <description>Frontend labels for indexed search</description>
+               <type>module</type>
+       </meta>
+       <data type="array">
+               <languageKey index="default" type="array">
+                       <label index="localizedOperandAnd">AND</label>
+                       <label index="localizedOperandOr">OR</label>
+                       <label index="localizedOperandNot">NOT</label>
+
+                       <label index="rules.headline">Rules</label>
+                       <label index="rules.text"><![CDATA[Only words with 2 or more characters are accepted<br />
+Max 200 chars total<br />
+Space is used to split words, "" can be used to search for a whole string (not indexed search then)<br />
+AND, OR and NOT are prefix words, overruling the default operator<br />
++/|/- equals AND, OR and NOT as operators.<br />
+All search words are converted to lowercase.
+]]></label>
+
+                       <label index="form.legend">Search form</label>
+                       <label index="form.searchFor">Search for</label>
+                       <label index="form.extResume">Extended resume</label>
+                       <label index="form.atATime">at a time</label>
+                       <label index="form.orderBy">Order by</label>
+                       <label index="form.fromSection">From section</label>
+                       <label index="form.freeIndexUid">Category</label>
+                       <label index="form.searchIn">Search in</label>
+                       <label index="form.match">Match</label>
+                       <label index="form.style">Style</label>
+                       <label index="form.submit">Search</label>
+                       <label index="form.addToSearch">Add to current search words</label>
+
+                       <label index="form.linkToRegularSearch">Regular search</label>
+                       <label index="form.linkToAdvancedSearch">Advanced search</label>
+
+
+                       <label index="types.0">Distinct word</label>
+                       <label index="types.1">Part of word</label>
+                       <label index="types.2">First part of word</label>
+                       <label index="types.3">Last part of word</label>
+                       <label index="types.10">Sounds like</label>
+                       <label index="types.20">Sentence</label>
+
+                       <label index="defaultOperands.0">All words (AND)</label>
+                       <label index="defaultOperands.1">Any words (OR)</label>
+
+                       <label index="languageUids.-1">All languages</label>
+                       <label index="languageUids.0">Default</label>
+
+                       <label index="sections.0">Whole site</label>
+                       <label index="sections.-1">Only this page</label>
+                       <label index="sections.-2">Top + level 1</label>
+                       <label index="sections.-3">Level 2 and out</label>
+                       <label index="sections.RL1">Level 1:</label>
+                       <label index="sections.RL1All">All pages on level 1</label>
+                       <label index="sections.RL2">- Level 2:</label>
+                       <label index="sections.RL2All">- All pages on level 2</label>
+
+                       <label index="mediaTypes.0">Internal pages</label>
+                       <label index="mediaTypes.-1">All media</label>
+                       <label index="mediaTypes.-2">All External</label>
+
+                       <label index="indexingConfigurations.-1">All, mixed</label>
+                       <label index="indexingConfigurations.-2">All, categorized</label>
+                       <label index="indexingConfigurations._0">Pages</label>
+
+                       <label index="indexingConfigurationHeader.-1">Mixed categories</label>
+                       <label index="indexingConfigurationHeader.0">Website Pages</label>
+
+                       <label index="sortOrders.rank_flag">Weight/Frequency</label>
+                       <label index="sortOrders.rank_freq">Frequency</label>
+                       <label index="sortOrders.rank_first">Close to top</label>
+                       <label index="sortOrders.rank_count">Number of words</label>
+                       <label index="sortOrders.mtime">Date Modified</label>
+                       <label index="sortOrders.title">Document title</label>
+                       <label index="sortOrders.crdate">Creation date</label>
+
+                       <label index="sortOrders.descending">Highest first</label>
+                       <label index="sortOrders.ascending">Lowest first</label>
+
+                       <label index="groupBy.sections">Section hierarchy</label>
+                       <label index="groupBy.flat">Flat list</label>
+
+                       <label index="result.page">page</label>
+                       <label index="result.pages">pages</label>
+                       <label index="result.unnamedSection">Other</label>
+                       <label index="result.otherMatching">Other matching pages in the same document:</label>
+                       <label index="result.otherPageAsWell">INFO: There was another page indexed as well. Probably indexed with another or no usergroup.</label>
+                       <label index="result.path">Path:</label>
+                       <label index="result.modified">Modified:</label>
+                       <label index="result.created">Created:</label>
+                       <label index="result.size">Size:</label>
+                       <label index="result.noResume">Note: This search hit may not accurately match the content on this page. The page resume cannot be shown.</label>
+                       <label index="result.memberGroups">Require membership of group numbers %s</label>
+
+                       <label index="result.ratingMatches">matches</label>
+                       <label index="result.noResult">No results found.</label>
+                       <label index="result.inSection">in the section</label>
+                       <label index="result.inNsection">in %s section:</label>
+                       <label index="result.inNsections">in %s sections:</label>
+
+                       <label index="searchFor">Search for</label>
+                       <label index="searchFor.or">or</label>
+                       <label index="searchFor.and">and</label>
+                       <label index="searchFor.andnot">but not</label>
+
+                       <label index="displayResults.previous">&lt; Previous</label>
+                       <label index="displayResults.page">Page</label>
+                       <label index="displayResults.next">Next &gt;</label>
+                       <label index="displayResults"><![CDATA[Displaying results <strong>%s to %s</strong> out of <strong>%s</strong>]]></label>
+               </languageKey>
+       </data>
+</T3locallang>
\ No newline at end of file
diff --git a/typo3/sysext/indexed_search/Resources/Private/Partials/Rules.html b/typo3/sysext/indexed_search/Resources/Private/Partials/Rules.html
new file mode 100644 (file)
index 0000000..b81206e
--- /dev/null
@@ -0,0 +1,6 @@
+<f:if condition="{settings.showRules}">
+<div class="tx-indexedsearch-rules">
+       <h2><f:translate key="rules.headline" /></h2>
+       <p><f:format.nl2br><f:translate key="rules.text" /></f:format.nl2br></p>
+</div>
+</f:if>
\ No newline at end of file
diff --git a/typo3/sysext/indexed_search/Resources/Private/Partials/Searchresult.html b/typo3/sysext/indexed_search/Resources/Private/Partials/Searchresult.html
new file mode 100644 (file)
index 0000000..92e5663
--- /dev/null
@@ -0,0 +1,32 @@
+<div class="tx-indexedsearch-res">
+       <f:format.html><h3><span class="tx-indexedsearch-icon">{row.icon}</span> <f:if condition="{settings.displayResultNumber}"><span class="tx-indexedsearch-result-number">{row.result_number}</span></f:if> <span class="tx-indexedsearch-title">{row.title}</span> <span class="tx-indexedsearch-percent">{row.rating}</span></h3></f:format.html>
+
+       <f:if condition="{row.headerOnly} == 0">
+       <p class="tx-indexedsearch-description">{row.description}</p>
+       <dl class="tx-indexedsearch-info">
+               <dt class="tx-indexedsearch-text-item-size"><f:translate key="result.size" />&nbsp;</dt>
+               <dd class="tx-indexedsearch-text-item-size">{row.size}</dd>
+
+               <dt class="tx-indexedsearch-text-item-crdate"><f:translate key="result.created" />&nbsp;</dt>
+               <dd class="tx-indexedsearch-text-item-crdate"><f:format.date>@{row.created}</f:format.date></dd>
+
+               <dt class="tx-indexedsearch-text-item-mtime"><f:translate key="result.modified" />&nbsp;</dt>
+               <dd class="tx-indexedsearch-text-item-mtime"><f:format.date>@{row.modified}</f:format.date></dd>
+
+               <dt class="tx-indexedsearch-text-item-path"><f:translate key="result.path" />&nbsp;</dt>
+               <dd class="tx-indexedsearch-text-item-path"><f:format.html>{row.path}</f:format.html></dd>
+       </dl>
+       </f:if>
+
+       <f:if condition="{row.headerOnly} == 1">
+               <p class="tx-indexedsearch-description">{row.description}</p>
+       </f:if>
+
+       <f:if condition="{row.subresults}">
+               <p class="tx-indexedsearch-list">
+                       <f:for each="{row.subresults.items}" as="subrow">
+                               <f:render partial="Searchresult" arguments="{row: subrow}" />
+                       </f:for>
+               </p>
+       </f:if>
+</div>
\ No newline at end of file
diff --git a/typo3/sysext/indexed_search/Resources/Private/Templates/Search/Form.html b/typo3/sysext/indexed_search/Resources/Private/Templates/Search/Form.html
new file mode 100644 (file)
index 0000000..30627c2
--- /dev/null
@@ -0,0 +1,121 @@
+<div class="tx-indexedsearch-searchbox">
+<f:form action="search" method="post" id="tx_indexedsearch" noCacheHash="true">
+       <div class="tx-indexedsearch-hidden-fields">
+               <f:form.hidden name="search[_sections]" value="0" />
+               <f:form.hidden name="search[_freeIndexUid]" id="tx_indexedsearch_freeIndexUid" value="_" />
+               <f:form.hidden name="search[pointer]" id="tx_indexedsearch_pointer" value="0" />
+               <f:form.hidden name="search[ext]" value="{searchParams.ext}" />
+               <f:form.hidden name="search[searchType]" value="{searchParams.searchType}" />
+               <f:form.hidden name="search[defaultOperand]" value="{searchParams.defaultOperand}" />
+               <f:form.hidden name="search[mediaType]" value="{searchParams.mediaType}" />
+               <f:form.hidden name="search[sortOrder]" value="{searchParams.sortOrder}" />
+               <f:form.hidden name="search[group]" value="{searchParams.group}" />
+               <f:form.hidden name="search[languageUid]" value="{searchParams.languageUid}" />
+               <f:form.hidden name="search[desc]" value="{searchParams.desc}" />
+               <f:form.hidden name="search[numberOfResults]" value="{searchParams.numberOfResults}" />
+       </div>
+
+       <fieldset>
+               <legend><f:translate key="form.legend" /></legend>
+
+               <div class="tx-indexedsearch-form">
+                       <label for="tx-indexedsearch-searchbox-sword"><f:translate key="form.searchFor" />:</label>
+                       <f:form.textfield name="search[sword]" value="{sword}" id="tx-indexedsearch-searchbox-sword" class="tx-indexedsearch-searchbox-sword" />
+               </div>
+
+               <f:if condition="{showAdditionalKeywordSearch}">
+                       <f:form.hidden name="search[sword_prev]" value="{previousSearchWord}" />
+                       <f:form.checkbox name="search[sword_prev_include]" id="tx_indexedsearch_sword_prev_include" value="1" checked="{searchParams.sword_prev}" /> <label for="tx_indexedsearch_sword_prev_include"><f:translate key="form.addToSearch" />.</label>
+               </f:if>
+
+               <f:if condition="{searchParams.extendedSearch}">
+                       <f:if condition="{showTypeSearch}">
+                               <div class="tx-indexedsearch-search-for">
+                                       <label for="tx-indexedsearch-selectbox-type"><f:translate key="form.match" />:</label>
+
+                                       <f:if condition="{allSearchTypes}">
+                                               <f:form.select name="search[searchType]" options="{allSearchTypes}" value="{searchParams.searchType}" id="tx-indexedsearch-selectbox-searchtype" class="tx-indexedsearch-selectbox-searchtype" />
+                                       </f:if>
+
+                                       <f:if condition="{allDefaultOperands}">
+                                               <f:form.select name="search[defaultOperand]" options="{allDefaultOperands}" value="{searchParams.defaultOperand}" id="tx-indexedsearch-selectbox-defaultoperand" class="tx-indexedsearch-selectbox-defaultoperand" />
+                                       </f:if>
+                               </div>
+                       </f:if>
+
+                       <f:if condition="{showMediaAndLanguageSearch}">
+                               <div class="tx-indexedsearch-search-in">
+                                       <label for="tx-indexedsearch-selectbox-media"><f:translate key="form.searchIn" />:</label>
+
+                                       <f:if condition="{allMediaTypes}">
+                                               <f:form.select name="search[mediaType]" options="{allMediaTypes}" value="{searchParams.mediaType}" id="tx-indexedsearch-selectbox-media" class="tx-indexedsearch-selectbox-media media" />
+                                       </f:if>
+
+                                       <f:if condition="{allLanguageUids}">
+                                               <f:form.select name="search[languageUid]" options="{allLanguageUids}" value="{searchParams.languageUid}" id="tx-indexedsearch-selectbox-lang" class="tx-indexedsearch-selectbox-lang lang" />
+                                       </f:if>
+                               </div>
+                       </f:if>
+
+                       <f:if condition="{allSections}">
+                               <div class="tx-indexedsearch-search-select-section">
+                                       <label for="tx-indexedsearch-selectbox-sections"><f:translate key="form.fromSection" />:</label>
+                                       <f:form.select name="search[sections]" options="{allSections}" value="{searchParams.sections}" id="tx-indexedsearch-selectbox-sections" class="tx-indexedsearch-selectbox-sections" />
+                               </div>
+                       </f:if>
+
+                       <f:if condition="{allIndexConfigurations}">
+                               <div class="tx-indexedsearch-search-freeindexuid">
+                                       <label for="tx-indexedsearch-selectbox-freeIndexUid"><f:translate key="form.freeIndexUid" />:</label>
+                                       <f:form.select name="search[freeIndexUid]" options="{allIndexConfigurations}" value="{searchParams.freeIndexUid}" id="tx-indexedsearch-selectbox-freeIndexUid" class="tx-indexedsearch-selectbox-freeIndexUid" />
+                               </div>
+                       </f:if>
+
+                       <f:if condition="{showSortOrders}">
+                               <div class="tx-indexedsearch-search-select-order">
+                                       <label for="tx-indexedsearch-selectbox-order"><f:translate key="form.orderBy" />:</label>
+                                       <f:form.select name="search[sortOrder]" options="{allSortOrders}" value="{searchParams.sortOrder}" id="tx-indexedsearch-selectbox-order" class="tx-indexedsearch-selectbox-order" />&nbsp;
+                                       <f:form.select name="search[sortDesc]"  options="{allSortDescending}" value="{searchParams.sortDesc}" id="tx-indexedsearch-selectbox-desc" class="tx-indexedsearch-selectbox-desc" />
+                               </div>
+                       </f:if>
+
+                       <f:if condition="{allNumberOfResults}">
+                               <div class="tx-indexedsearch-search-select-results">
+                                       <label for="tx-indexedsearch-selectbox-results"><f:translate key="form.atATime" /></label>
+                                       <f:form.select name="search[numberOfResults]" options="{allNumberOfResults}" value="{searchParams.numberOfResults}" id="tx-indexedsearch-selectbox-results" class="tx-indexedsearch-selectbox-results" />
+                               </div>
+                       </f:if>
+
+                       <f:if condition="{allGroups}">
+                               <div class="tx-indexedsearch-search-select-group">
+                                       <label for="tx-indexedsearch-selectbox-group"><f:translate key="form.style" />:</label>
+                                       <f:form.select name="search[group]" options="{allGroups}" value="{searchParams.group}" id="tx-indexedsearch-selectbox-group" class="tx-indexedsearch-selectbox-group" />
+                                       <f:if condition="{settings.blind.extResume} == 0">
+                                               <f:form.checkbox name="tx_indexedsearch[extResume]" id="tx_indexedsearch_extResume" checked="{searchParams.extResume}" value="1" />
+                                       </f:if>
+                               </div>
+                       </f:if>
+               </f:if>
+
+               <div class="tx-indexedsearch-search-submit">
+                       <f:form.submit name="search[submitButton]" value="{f:translate(key: 'form.submit')}" id="tx-indexedsearch-searchbox-button-submit" class="tx-indexedsearch-searchbox-button" />
+               </div>
+       </fieldset>
+
+
+       <f:if condition="{settings.displayAdvancedSearchLink}">
+               <p>
+               <f:if condition="{searchParams.extendedSearch}">
+                       <f:then>
+                               <f:link.action action="form" arguments="{extendedSearch: 0}"><f:translate key="form.linkToRegularSearch" /></f:link.action>
+                       </f:then>
+                       <f:else>
+                               <f:link.action action="form" arguments="{extendedSearch: 1}"><f:translate key="form.linkToExtendedSearch" /></f:link.action>
+                       </f:else>
+               </f:if>
+               </p>
+       </f:if>
+</f:form>
+</div>
+
+<f:render partial="Rules" />
\ No newline at end of file
diff --git a/typo3/sysext/indexed_search/Resources/Private/Templates/Search/Search.html b/typo3/sysext/indexed_search/Resources/Private/Templates/Search/Search.html
new file mode 100644 (file)
index 0000000..b6804fd
--- /dev/null
@@ -0,0 +1,71 @@
+{namespace is=Tx_IndexedSearch_ViewHelpers}
+
+<f:for each="{resultsets}" as="result">
+       <f:if condition="{result.categoryTitle}">
+               <h1 class="tx-indexedsearch-category">{result.categoryTitle}</h1>
+       </f:if>
+       
+       <!-- show the info what was searched for -->
+       <f:for each="{searchWords}" as="searchWord" key="key">
+               <f:if condition="{key} > 0">
+                       <f:then>
+                               <f:translate key="searchFor.{searchWord.oper}" />&nbsp;{searchWord.sword}
+                       </f:then>
+                       <f:else>
+                               <f:translate key="searchFor" />&nbsp;{searchWord.sword}
+                       </f:else>
+               </f:if>
+       </f:for>
+
+       <!-- show the info in which section was searched for -->
+       {result.searchedInSectionInfo}
+       <f:if condition="{result.count} > 0">
+               <f:then>
+                       <div class="tx-indexedsearch-browsebox">
+                               <!-- render the anchor-links to the sections inside the displayed result rows -->
+                               <f:if condition="{result.affectedSections}">
+                                       <div class="tx-indexedsearch-sectionlinks">
+                                               <table cellpadding="0" cellspacing="0" border="0" summary="Result links">
+                                                       <f:for each="{result.affectedSections}" as="sectionData" key="sectionId">
+                                                               <tr>
+                                                                       <td width="100%">--&gt;&nbsp;
+                                                                               <a href="#anchor_{sectionId}">
+                                                                                       <f:if condition="{sectionData.0}">
+                                                                                               <f:then>{sectionData.0}</f:then>
+                                                                                               <f:else><f:translate key="unnamedSection" /></f:else>
+                                                                                       </f:if>
+                                                                                       &nbsp;({sectionData.1}&nbsp;<f:translate key="{f:if(condition: '{sectionData.1} > 1', then: 'word_pages', else: 'word_pages')}" />)
+                                                                               </a>
+                                                                       </td>
+                                                               </tr>
+                                                       </f:for>
+                                               </table>
+                                       </div>
+                               </f:if>
+                               <p>
+                                       <is:pageBrowsingResults numberOfResults="{result.count}" currentPage="{searchData.pointer}" resultsPerPage="{searchData.results}" />
+                                       {result.sectionText}
+                               </p>
+                               <is:pageBrowsing maximumNumberOfResultPages="{settings.search.page_links}" numberOfResults="{result.count}" currentPage="{searchData.pointer}" resultsPerPage="{result.pageBrowser.resultsPerPage}" />
+                       </div>
+                       <f:for each="{result.rows}" as="row">
+                               <f:if condition="{row.isSectionHeader}">
+                                       <f:then>
+                                       <div id="{row.anchorId}" class="tx-indexedsearch-sectionhead">
+                                               <h2 class="tx-indexedsearch-title">{row.sectionTitle} <span class="tx-indexedsearch-result-count">{row.numResultRows} <f:translate key="{f:if(condition: '{row.numResultRows} > 1', then: 'result.pages', else: 'result.page')}" /></span></h2>
+                                       </div>
+                                       </f:then>
+                                       <f:else>
+                                               <f:render partial="Searchresult" arguments="{row: row}" />
+                                       </f:else>
+                               </f:if>
+                       </f:for>
+                       <div class="tx-indexedsearch-browsebox">
+                               <is:pageBrowsing numberOfResults="{result.count}" maximumNumberOfResultPages="{settings.search.page_links}" currentPage="{searchData.pointer}" resultsPerPage="{searchData.results}" />
+                       </div>
+               </f:then>
+               <f:else>
+                       <f:translate key="result.noResult" />
+               </f:else>
+       </f:if>
+</f:for>
\ No newline at end of file
index fc4dc18..193242b 100644 (file)
@@ -1,4 +1,7 @@
 <?php
+/*
+ * Register necessary class names with autoloader
+ */
 
 $extensionPath = t3lib_extMgm::extPath('indexed_search');
 return array(
@@ -6,4 +9,4 @@ return array(
        'tx_indexedsearch_util' => $extensionPath . 'class.tx_indexedsearch_util.php',
 );
 
-?>
\ No newline at end of file
+?>
index 5e9be9a..74676cc 100755 (executable)
@@ -3,7 +3,7 @@
 ########################################################################
 # Extension Manager/Repository config file for ext "indexed_search".
 #
-# Auto generated 24-08-2010 14:45
+# Auto generated 30-11-2011 14:26
 #
 # Manual updates:
 # Only the data in the array - everything else is removed by next
@@ -15,7 +15,7 @@ $EM_CONF[$_EXTKEY] = array(
        'description' => 'Indexed Search Engine for TYPO3 pages, PDF-files, Word-files, HTML and text files. Provides a backend module for statistics of the indexer and a frontend plugin. Documentation can be found in the extension "doc_indexed_search".',
        'category' => 'plugin',
        'shy' => 0,
-       'dependencies' => 'cms',
+       'dependencies' => '',
        'conflicts' => '',
        'priority' => '',
        'loadOrder' => '',
@@ -25,7 +25,7 @@ $EM_CONF[$_EXTKEY] = array(
        'uploadfolder' => 0,
        'createDirs' => '',
        'modify_tables' => '',
-       'clearCacheOnLoad' => 1,
+       'clearCacheOnLoad' => 0,
        'lockType' => '',
        'author' => 'Kasper Skaarhoj',
        'author_email' => 'kasperYYYY@typo3.com',
@@ -33,21 +33,21 @@ $EM_CONF[$_EXTKEY] = array(
        'CGLcompliance' => '',
        'CGLcompliance_note' => '',
        'version' => '2.12.0',
-       '_md5_values_when_last_written' => 'a:56:{s:9:"ChangeLog";s:4:"7479";s:17:"class.crawler.php";s:4:"fabe";s:25:"class.doublemetaphone.php";s:4:"28e4";s:25:"class.external_parser.php";s:4:"b3f9";s:17:"class.indexer.php";s:4:"bf71";s:15:"class.lexer.php";s:4:"72fd";s:21:"ext_conf_template.txt";s:4:"0c64";s:12:"ext_icon.gif";s:4:"4cbf";s:17:"ext_localconf.php";s:4:"4c42";s:14:"ext_tables.php";s:4:"3a84";s:14:"ext_tables.sql";s:4:"7084";s:28:"ext_typoscript_editorcfg.txt";s:4:"0a34";s:24:"ext_typoscript_setup.txt";s:4:"9b5f";s:13:"locallang.xml";s:4:"cd0c";s:26:"locallang_csh_indexcfg.xml";s:4:"f4f3";s:16:"locallang_db.xml";s:4:"f142";s:7:"tca.php";s:4:"f24a";s:12:"cli/conf.php";s:4:"19fe";s:14:"doc/README.txt";s:4:"a737";s:12:"doc/TODO.txt";s:4:"c804";s:29:"example/class.crawlerhook.php";s:4:"626a";s:24:"example/class.pihook.php";s:4:"bf31";s:46:"hooks/class.tx_indexedsearch_tslib_fe_hook.php";s:4:"c27f";s:13:"mod/clear.gif";s:4:"cc11";s:12:"mod/conf.php";s:4:"9062";s:13:"mod/index.php";s:4:"c619";s:15:"mod/isearch.gif";s:4:"4cbf";s:21:"mod/locallang_mod.xml";s:4:"1624";s:21:"mod/mod_template.html";s:4:"a7f2";s:44:"modfunc1/class.tx_indexedsearch_modfunc1.php";s:4:"e6d8";s:22:"modfunc1/locallang.xml";s:4:"4806";s:44:"modfunc2/class.tx_indexedsearch_modfunc2.php";s:4:"81bb";s:22:"modfunc2/locallang.xml";s:4:"a889";s:29:"pi/class.tx_indexedsearch.php";s:4:"d0cf";s:21:"pi/considerations.txt";s:4:"e3df";s:22:"pi/indexed_search.tmpl";s:4:"4b28";s:16:"pi/locallang.xml";s:4:"4f34";s:20:"pi/template_css.tmpl";s:4:"0df0";s:14:"pi/res/csv.gif";s:4:"e413";s:14:"pi/res/doc.gif";s:4:"0975";s:15:"pi/res/html.gif";s:4:"5647";s:14:"pi/res/jpg.gif";s:4:"23ac";s:17:"pi/res/locked.gif";s:4:"c212";s:16:"pi/res/pages.gif";s:4:"1923";s:14:"pi/res/pdf.gif";s:4:"9451";s:14:"pi/res/pps.gif";s:4:"926b";s:14:"pi/res/ppt.gif";s:4:"ada5";s:14:"pi/res/rtf.gif";s:4:"f660";s:14:"pi/res/sxc.gif";s:4:"00a6";s:14:"pi/res/sxi.gif";s:4:"ef83";s:14:"pi/res/sxw.gif";s:4:"4a8f";s:14:"pi/res/tif.gif";s:4:"533b";s:14:"pi/res/txt.gif";s:4:"c576";s:14:"pi/res/xls.gif";s:4:"4a22";s:14:"pi/res/xml.gif";s:4:"2e7b";s:38:"tests/tx_indexedsearch_indexerTest.php";s:4:"22ed";}',
+       '_md5_values_when_last_written' => 'a:69:{s:9:"ChangeLog";s:4:"7479";s:17:"class.crawler.php";s:4:"ec8d";s:25:"class.doublemetaphone.php";s:4:"3b62";s:25:"class.external_parser.php";s:4:"ad1e";s:17:"class.indexer.php";s:4:"deda";s:15:"class.lexer.php";s:4:"c88d";s:31:"class.tx_indexedsearch_util.php";s:4:"9e93";s:16:"ext_autoload.php";s:4:"c367";s:21:"ext_conf_template.txt";s:4:"91e1";s:12:"ext_icon.gif";s:4:"4cbf";s:17:"ext_localconf.php";s:4:"0f26";s:14:"ext_tables.php";s:4:"0cbd";s:14:"ext_tables.sql";s:4:"c442";s:28:"ext_typoscript_editorcfg.txt";s:4:"0a34";s:24:"ext_typoscript_setup.txt";s:4:"0d9e";s:13:"locallang.xlf";s:4:"94af";s:26:"locallang_csh_indexcfg.xlf";s:4:"5d7c";s:16:"locallang_db.xlf";s:4:"0a5e";s:7:"tca.php";s:4:"f24a";s:39:"Classes/Controller/SearchController.php";s:4:"022d";s:51:"Classes/Domain/Repository/IndexSearchRepository.php";s:4:"e21f";s:53:"Classes/ViewHelpers/PageBrowsingResultsViewHelper.php";s:4:"7c0e";s:46:"Classes/ViewHelpers/PageBrowsingViewHelper.php";s:4:"f2ee";s:38:"Configuration/TypoScript/constants.txt";s:4:"694e";s:34:"Configuration/TypoScript/setup.txt";s:4:"97af";s:40:"Resources/Private/Language/locallang.xml";s:4:"8a28";s:37:"Resources/Private/Partials/Rules.html";s:4:"4737";s:44:"Resources/Private/Partials/Searchresult.html";s:4:"e397";s:44:"Resources/Private/Templates/Search/Form.html";s:4:"bef9";s:46:"Resources/Private/Templates/Search/Search.html";s:4:"1091";s:12:"cli/conf.php";s:4:"19fe";s:14:"doc/README.txt";s:4:"0a8e";s:12:"doc/TODO.txt";s:4:"c804";s:29:"example/class.crawlerhook.php";s:4:"6662";s:24:"example/class.pihook.php";s:4:"f7dd";s:46:"hooks/class.tx_indexedsearch_tslib_fe_hook.php";s:4:"1bb8";s:13:"mod/clear.gif";s:4:"cc11";s:12:"mod/conf.php";s:4:"7a2f";s:13:"mod/index.php";s:4:"378e";s:15:"mod/isearch.gif";s:4:"4cbf";s:21:"mod/locallang_mod.xlf";s:4:"e903";s:21:"mod/mod_template.html";s:4:"a7f2";s:44:"modfunc1/class.tx_indexedsearch_modfunc1.php";s:4:"12ff";s:22:"modfunc1/locallang.xlf";s:4:"0abc";s:44:"modfunc2/class.tx_indexedsearch_modfunc2.php";s:4:"edce";s:22:"modfunc2/locallang.xlf";s:4:"6e83";s:29:"pi/class.tx_indexedsearch.php";s:4:"4165";s:21:"pi/considerations.txt";s:4:"07ed";s:22:"pi/indexed_search.tmpl";s:4:"4b28";s:16:"pi/locallang.xlf";s:4:"c0a4";s:20:"pi/template_css.tmpl";s:4:"5251";s:14:"pi/res/csv.gif";s:4:"6a23";s:14:"pi/res/doc.gif";s:4:"2ec9";s:15:"pi/res/html.gif";s:4:"5647";s:14:"pi/res/jpg.gif";s:4:"e8df";s:17:"pi/res/locked.gif";s:4:"c212";s:16:"pi/res/pages.gif";s:4:"1405";s:14:"pi/res/pdf.gif";s:4:"9451";s:14:"pi/res/pps.gif";s:4:"926b";s:14:"pi/res/ppt.gif";s:4:"ada5";s:14:"pi/res/rtf.gif";s:4:"f660";s:14:"pi/res/sxc.gif";s:4:"00a6";s:14:"pi/res/sxi.gif";s:4:"4223";s:14:"pi/res/sxw.gif";s:4:"4a8f";s:14:"pi/res/tif.gif";s:4:"533b";s:14:"pi/res/txt.gif";s:4:"0004";s:14:"pi/res/xls.gif";s:4:"f106";s:14:"pi/res/xml.gif";s:4:"c32d";s:38:"tests/tx_indexedsearch_indexerTest.php";s:4:"3bb1";}',
        'constraints' => array(
                'depends' => array(
-                       'cms' => '',
                        'php' => '5.1.0-0.0.0',
                        'typo3' => '4.4.0-0.0.0',
                ),
                'conflicts' => array(
                ),
                'suggests' => array(
-                       'doc_indexed_search' => '',
+                       'extbase' => '',
+                       'fluid' => ''
                ),
        ),
        'suggests' => array(
        ),
 );
 
-?>
\ No newline at end of file
+?>
index 982069e..6cef67a 100755 (executable)
@@ -7,6 +7,17 @@ t3lib_extMgm::addTypoScript($_EXTKEY,'editorcfg','
        tt_content.CSS_editor.ch.tx_indexedsearch = < plugin.tx_indexedsearch.CSS_editor
 ',43);
 
+if (t3lib_extMgm::isLoaded('extbase')) {
+       // Configure the Extbase Plugin
+       Tx_Extbase_Utility_Extension::configurePlugin(
+               $_EXTKEY, 'Pi2',
+                       // array holding the controller-action-combinations that are accessible
+               array('Search' => 'form,search'),
+                       // array of non-cachable controller-action-combinations (they must already be enabled above)
+               array('Search' => 'form,search')
+       );
+}
+
        // Attach to hooks:
 $TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageIndexing'][] = 'EXT:indexed_search/class.indexer.php:tx_indexedsearch_indexer';
 $TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['headerNoCache']['tx_indexedsearch'] = 'EXT:indexed_search/hooks/class.tx_indexedsearch_tslib_fe_hook.php:&tx_indexedsearch_tslib_fe_hook->headerNoCache';
@@ -75,4 +86,4 @@ $TYPO3_CONF_VARS['EXTCONF']['indexed_search']['pi1_hooks'] = array (
 /*
        $TYPO3_CONF_VARS['EXTCONF']['indexed_search']['crawler']['tx_myext_example1'] = 'EXT:indexed_search/example/class.crawlerhook.php:&tx_indexedsearch_crawlerhook';
 */
-?>
\ No newline at end of file
+?>
index 5f74258..4c44812 100755 (executable)
@@ -6,6 +6,17 @@ t3lib_extMgm::addPlugin(Array('LLL:EXT:indexed_search/locallang.php:mod_indexed_
 t3lib_div::loadTCA('tt_content');
 $TCA['tt_content']['types']['list']['subtypes_excludelist'][$_EXTKEY] = 'layout,select_key,pages';
 
+// Registers the Extbase plugin to be listed in the Backend.
+if (t3lib_extMgm::isLoaded('extbase')) {
+       $extensionName = t3lib_div::underscoredToUpperCamelCase($_EXTKEY);
+               Tx_Extbase_Utility_Extension::registerPlugin($_EXTKEY, 'Pi2',
+                       // the title shown in the backend dropdown field
+               'Indexed Search (experimental)'
+       );
+       $pluginSignature = strtolower($extensionName) . '_pi2';
+       $TCA['tt_content']['types']['list']['subtypes_excludelist'][$pluginSignature] = 'layout,select_key,pages,recursive';
+}
+
 if (TYPO3_MODE=='BE')    {
        t3lib_extMgm::addModule('tools','isearch','after:log',t3lib_extMgm::extPath($_EXTKEY).'mod/');
 
index ec05d07..ed15c24 100755 (executable)
@@ -51,7 +51,7 @@ plugin.tx_indexedsearch {
                rootPidList =
                page_links = 10
                detect_sys_domain_records = 0
-               defaultFreeIndexUidList =
+               defaultFreeIndexUidList = -1
                skipExtendToSubpagesChecking = 0
                exactCount = 0
                targetPid.data = TSFE:id