Fixed bug #9994: ereg* is deprecated in PHP 5.3 alpha3
[Packages/TYPO3.CMS.git] / typo3 / sysext / indexed_search / pi / class.tx_indexedsearch.php
index e1f5b8f..18a0f4e 100755 (executable)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2001-2005 Kasper Skaarhoj (kasperYYYY@typo3.com)
+*  (c) 2001-2009 Kasper Skaarhoj (kasperYYYY@typo3.com)
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -32,7 +32,7 @@
  * Creates a searchform for indexed search. Indexing must be enabled
  * for this to make sense.
  *
- * @author     Kasper Skårhøj <kasperYYYY@typo3.com>
+ * @author     Kasper Skaarhoj <kasperYYYY@typo3.com>
  * @co-author  Christian Jul Jensen <christian@typo3.com>
  */
 /**
  *
  *
  *
- *  121: class tx_indexedsearch extends tslib_pibase
- *  165:     function main($content, $conf)
- *  198:     function initialize()
- *  381:     function getSearchWords($defOp)
- *  415:     function procSearchWordsByLexer($SWArr)
+ *  123: class tx_indexedsearch extends tslib_pibase
+ *  168:     function main($content, $conf)
+ *  200:     function initialize()
+ *  413:     function getSearchWords($defOp)
+ *  447:     function procSearchWordsByLexer($SWArr)
  *
  *              SECTION: Main functions
- *  459:     function doSearch($sWArr)
- *  492:     function getResultRows($sWArr)
- *  562:     function getResultRows_SQLpointer($sWArr)
- *  582:     function getDisplayResults($sWArr, $resData)
- *  633:     function compileResult($resultRows)
+ *  491:     function doSearch($sWArr)
+ *  549:     function getResultRows($sWArr,$freeIndexUid=-1)
+ *  623:     function getResultRows_SQLpointer($sWArr,$freeIndexUid=-1)
+ *  647:     function getDisplayResults($sWArr, $resData, $freeIndexUid=-1)
+ *  699:     function compileResult($resultRows, $freeIndexUid=-1)
  *
  *              SECTION: Searching functions (SQL)
- *  726:     function getPhashList($sWArr)
- *  827:     function execPHashListQuery($wordSel,$plusQ='')
- *  847:     function sectionTableWhere()
- *  894:     function mediaTypeWhere()
- *  919:     function languageWhere()
- *  931:     function execFinalQuery($list)
- * 1069:     function checkResume($row)
- * 1116:     function isDescending($inverse=FALSE)
- * 1130:     function writeSearchStat($sWArr,$count,$pt)
+ *  800:     function getPhashList($sWArr)
+ *  901:     function execPHashListQuery($wordSel,$plusQ='')
+ *  921:     function sectionTableWhere()
+ *  968:     function mediaTypeWhere()
+ *  993:     function languageWhere()
+ * 1005:     function freeIndexUidWhere($freeIndexUid)
+ * 1046:     function execFinalQuery($list,$freeIndexUid=-1)
+ * 1189:     function checkResume($row)
+ * 1236:     function isDescending($inverse=FALSE)
+ * 1250:     function writeSearchStat($sWArr,$count,$pt)
  *
  *              SECTION: HTML output functions
- * 1181:     function makeSearchForm($optValues)
- * 1253:     function printRules()
- * 1269:     function printResultSectionLinks()
- * 1291:     function makeSectionHeader($id,$sectionTitleLinked,$countResultRows)
- * 1307:     function printResultRow($row, $headerOnly=0)
- * 1382:     function pi_list_browseresults($showResultCount=1,$addString='',$addPart='')
+ * 1302:     function makeSearchForm($optValues)
+ * 1436:     function renderSelectBoxValues($value,$optValues)
+ * 1455:     function printRules()
+ * 1474:     function printResultSectionLinks()
+ * 1508:     function makeSectionHeader($id, $sectionTitleLinked, $countResultRows)
+ * 1529:     function printResultRow($row, $headerOnly=0)
+ * 1598:     function pi_list_browseresults($showResultCount=1,$addString='',$addPart='',$freeIndexUid=-1)
  *
  *              SECTION: Support functions for HTML output (with a minimum of fixed markup)
- * 1445:     function prepareResultRowTemplateData($row, $headerOnly)
- * 1489:     function tellUsWhatIsSeachedFor($sWArr)
- * 1523:     function wrapSW($str)
- * 1535:     function renderSelectBox($name,$value,$optValues)
- * 1558:     function makePointerSelector_link($str,$p)
- * 1571:     function makeItemTypeIcon($it,$alt='',$specRowConf)
- * 1613:     function makeRating($row)
- * 1658:     function makeDescription($row,$noMarkup=0,$lgd=180)
- * 1688:     function markupSWpartsOfString($str)
- * 1768:     function makeTitle($row)
- * 1792:     function makeInfo($row,$tmplArray)
- * 1817:     function getSpecialConfigForRow($row)
- * 1841:     function makeLanguageIndication($row)
- * 1878:     function makeAccessIndication($id)
- * 1892:     function linkPage($id,$str,$row=array())
- * 1935:     function getRootLine($id,$pathMP='')
- * 1950:     function getFirstSysDomainRecordForPage($id)
- * 1963:     function getPathFromPageId($id,$pathMP='')
- * 2015:     function getMenu($id)
- * 2034:     function multiplePagesType($item_type)
- * 2044:     function utf8_to_currentCharset($str)
- * 2054:     function &hookRequest($functionName)
+ * 1686:     function prepareResultRowTemplateData($row, $headerOnly)
+ * 1740:     function tellUsWhatIsSeachedFor($sWArr)
+ * 1774:     function wrapSW($str)
+ * 1786:     function renderSelectBox($name,$value,$optValues)
+ * 1810:     function makePointerSelector_link($str,$p,$freeIndexUid)
+ * 1825:     function makeItemTypeIcon($it,$alt='',$specRowConf)
+ * 1867:     function makeRating($row)
+ * 1911:     function makeDescription($row,$noMarkup=0,$lgd=180)
+ * 1942:     function markupSWpartsOfString($str)
+ * 2022:     function makeTitle($row)
+ * 2046:     function makeInfo($row,$tmplArray)
+ * 2075:     function getSpecialConfigForRow($row)
+ * 2099:     function makeLanguageIndication($row)
+ * 2142:     function makeAccessIndication($id)
+ * 2157:     function linkPage($id,$str,$row=array(),$markUpSwParams=array())
+ * 2201:     function getRootLine($id,$pathMP='')
+ * 2216:     function getFirstSysDomainRecordForPage($id)
+ * 2229:     function getPathFromPageId($id,$pathMP='')
+ * 2281:     function getMenu($id)
+ * 2300:     function multiplePagesType($item_type)
+ * 2310:     function utf8_to_currentCharset($str)
+ * 2320:     function &hookRequest($functionName)
  *
- * TOTAL FUNCTIONS: 46
+ * TOTAL FUNCTIONS: 48
  * (This index is automatically created/updated by the extension "extdeveval")
  *
  */
@@ -116,15 +118,15 @@ require_once(t3lib_extMgm::extPath('indexed_search').'class.indexer.php');
  *
  * @package TYPO3
  * @subpackage tx_indexedsearch
- * @author     Kasper Skårhøj <kasperYYYY@typo3.com>
+ * @author     Kasper Skaarhoj <kasperYYYY@typo3.com>
  */
 class tx_indexedsearch extends tslib_pibase {
-    var $prefixId = 'tx_indexedsearch';        // Same as class name
-    var $scriptRelPath = 'pi/class.tx_indexedsearch.php';    // Path to this script relative to the extension dir.
-    var $extKey = 'indexed_search';    // The extension key.
+       var $prefixId = 'tx_indexedsearch';        // Same as class name
+       var $scriptRelPath = 'pi/class.tx_indexedsearch.php';    // Path to this script relative to the extension dir.
+       var $extKey = 'indexed_search';    // The extension key.
 
        var $join_pages = 0;    // See document for info about this flag...
-       var $defaultResultNumber = 20;
+       var $defaultResultNumber = 10;
 
        var $operator_translate_table = Array (         // case-sensitive. Defines the words, which will be operators between words
                Array ('+' , 'AND'),
@@ -144,15 +146,30 @@ class tx_indexedsearch extends tslib_pibase {
        var $optValues = array();               // Selector box values for search configuration form
        var $firstRow = Array();                // Will hold the first row in result - used to calculate relative hit-ratings.
 
-       var $cache_path = array();                      // Caching of page path
-       var $cache_rl = array();                        // Caching of root line data
-       var $fe_groups_required = array();              // Required fe_groups memberships for display of a result.
-       var $domain_records = array();                  // Domain records (?)
-       var $wSelClauses = array();                             // Select clauses for individual words
-       var $resultSections = array();                  // Page tree sections for search result.
-       var $external_parsers = array();                // External parser objects
-       var $iconFileNameCache = array();               // Storage of icons....
-       var $lexerObj;                                                  // Lexer object
+       var $cache_path = array();              // Caching of page path
+       var $cache_rl = array();                // Caching of root line data
+       var $fe_groups_required = array();      // Required fe_groups memberships for display of a result.
+       var $domain_records = array();          // Domain records (?)
+       var $wSelClauses = array();             // Select clauses for individual words
+       var $resultSections = array();          // Page tree sections for search result.
+       var $external_parsers = array();        // External parser objects
+       var $iconFileNameCache = array();       // Storage of icons....
+
+       /**
+        * Lexer object
+        *
+        * @var tx_indexedsearch_lexer
+        */
+       var $lexerObj;
+
+       /**
+        * Indexer object
+        *
+        * @var tx_indexedsearch_indexer
+        */
+       var $indexerObj;
+       var $templateCode;                      // Will hold the content of $conf['templateFile']
+       var $hiddenFieldList = 'ext, type, defOp, media, order, group, lang, desc, results';
 
 
        /**
@@ -165,8 +182,8 @@ class tx_indexedsearch extends tslib_pibase {
        function main($content, $conf)    {
 
                        // Initialize:
-        $this->conf = $conf;
-        $this->pi_loadLL();
+               $this->conf = $conf;
+               $this->pi_loadLL();
                $this->pi_setPiVarDefaults();
 
                        // Initialize the indexer-class - just to use a few function (for making hashes)
@@ -182,10 +199,9 @@ class tx_indexedsearch extends tslib_pibase {
                }
 
                        // Finally compile all the content, form, messages and results:
-        $content=
-                       $this->makeSearchForm($this->optValues).
+               $content = $this->makeSearchForm($this->optValues).
                        $this->printRules().
-           $content;
+                       $content;
 
         return $this->pi_wrapInBaseClass($content);
     }
@@ -200,7 +216,7 @@ class tx_indexedsearch extends tslib_pibase {
 
                        // Initialize external document parsers for icon display and other soft operations
                if (is_array($TYPO3_CONF_VARS['EXTCONF']['indexed_search']['external_parsers']))        {
-                       foreach($TYPO3_CONF_VARS['EXTCONF']['indexed_search']['external_parsers'] as $extension => $_objRef)    {
+                       foreach ($TYPO3_CONF_VARS['EXTCONF']['indexed_search']['external_parsers'] as $extension => $_objRef)   {
                                $this->external_parsers[$extension] = &t3lib_div::getUserObj($_objRef);
 
                                        // Init parser and if it returns false, unset its entry again:
@@ -219,6 +235,9 @@ class tx_indexedsearch extends tslib_pibase {
                        // If "_sections" is set, this value overrides any existing value.
                if ($this->piVars['_sections'])         $this->piVars['sections'] = $this->piVars['_sections'];
 
+                       // If "_sections" is set, this value overrides any existing value.
+               if ($this->piVars['_freeIndexUid']!=='_')               $this->piVars['freeIndexUid'] = $this->piVars['_freeIndexUid'];
+
                        // Add previous search words to current
                if ($this->piVars['sword_prev_include'] && $this->piVars['sword_prev']) {
                        $this->piVars['sword'] = trim($this->piVars['sword_prev']).' '.$this->piVars['sword'];
@@ -247,6 +266,11 @@ class tx_indexedsearch extends tslib_pibase {
                                '-3' => $this->pi_getLL('opt_sections_-3'),
                                // 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.
                        ),
+                       'freeIndexUid' => Array(
+                               '-1' => $this->pi_getLL('opt_freeIndexUid_-1'),
+                               '-2' => $this->pi_getLL('opt_freeIndexUid_-2'),
+                               '0' => $this->pi_getLL('opt_freeIndexUid_0'),
+                       ),
                        'media' => Array(
                                '-1' => $this->pi_getLL('opt_media_-1'),
                                '0' => $this->pi_getLL('opt_media_0'),
@@ -281,8 +305,31 @@ class tx_indexedsearch extends tslib_pibase {
                        )
                );
 
+                       // Free Index Uid:
+               if ($this->conf['search.']['defaultFreeIndexUidList'])  {
+                       $uidList = t3lib_div::intExplode(',', $this->conf['search.']['defaultFreeIndexUidList']);
+                       $indexCfgRecords = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,title','index_config','uid IN ('.implode(',',$uidList).')'.$this->cObj->enableFields('index_config'),'','','','uid');
+
+                       foreach ($uidList as $uidValue) {
+                               if (is_array($indexCfgRecords[$uidValue]))      {
+                                       $this->optValues['freeIndexUid'][$uidValue] = $indexCfgRecords[$uidValue]['title'];
+                               }
+                       }
+               }
+
+                       // Should we use join_pages instead of long lists of uids?
+               if ($this->conf['search.']['skipExtendToSubpagesChecking'])     {
+                       $this->join_pages = 1;
+               }
+
                        // Add media to search in:
-               foreach($this->external_parsers as $extension => $obj)  {
+               if (strlen(trim($this->conf['search.']['mediaList'])))  {
+                       $mediaList = implode(',', t3lib_div::trimExplode(',', $this->conf['search.']['mediaList'], 1));
+               }
+               foreach ($this->external_parsers as $extension => $obj) {
+                               // Skip unwanted extensions
+                       if ($mediaList && !t3lib_div::inList($mediaList, $extension))   { continue; }
+
                        if ($name = $obj->searchTypeMediaTitle($extension))     {
                                $this->optValues['media'][$extension] = $this->pi_getLL('opt_sections_'.$extension,$name);
                        }
@@ -302,12 +349,14 @@ class tx_indexedsearch extends tslib_pibase {
                if ($this->conf['show.']['L1sections']) {
                        $firstLevelMenu = $this->getMenu($this->wholeSiteIdList);
                        while(list($kk,$mR) = each($firstLevelMenu))    {
-                               if ($mR['doktype']!=5)  {
+                                       // @TODO: RFC #7370: doktype 2&5 are deprecated since TYPO3 4.2-beta1
+                               if ($mR['doktype']!=5 && !$mR['nav_hide']) {
                                        $this->optValues['sections']['rl1_'.$mR['uid']] = trim($this->pi_getLL('opt_RL1').' '.$mR['title']);
                                        if ($this->conf['show.']['L2sections']) {
                                                $secondLevelMenu = $this->getMenu($mR['uid']);
                                                while(list($kk2,$mR2) = each($secondLevelMenu)) {
-                                                       if ($mR['doktype']!=5)  {
+                                                               // @TODO: RFC #7370: doktype 2&5 are deprecated since TYPO3 4.2-beta1
+                                                       if ($mR2['doktype']!=5 && !$mR2['nav_hide']) {
                                                                $this->optValues['sections']['rl2_'.$mR2['uid']] = trim($this->pi_getLL('opt_RL2').' '.$mR2['title']);
                                                        } else unset($secondLevelMenu[$kk2]);
                                                }
@@ -324,6 +373,9 @@ class tx_indexedsearch extends tslib_pibase {
                        $this->wholeSiteIdList = implode(',',t3lib_div::intExplode(',',$this->conf['search.']['rootPidList']));
                }
 
+                       // Load the template
+               $this->templateCode = $this->cObj->fileResource($this->conf['templateFile']);
+
                        // Add search languages:
                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_language', '1=1'.$this->cObj->enableFields('sys_language'));
                while($lR = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))        {
@@ -337,7 +389,7 @@ class tx_indexedsearch extends tslib_pibase {
 
                        // Default values set:
                        // Setting first values in optValues as default values IF there is not corresponding piVar value set already.
-               foreach($this->optValues as $kk => $vv) {
+               foreach ($this->optValues as $kk => $vv)        {
                        if (!isset($this->piVars[$kk])) {
                                reset($vv);
                                $this->piVars[$kk] = key($vv);
@@ -346,9 +398,9 @@ class tx_indexedsearch extends tslib_pibase {
 
                        // Blind selectors:
                if (is_array($this->conf['blind.']))    {
-                       foreach($this->conf['blind.'] as $kk => $vv)    {
+                       foreach ($this->conf['blind.'] as $kk => $vv)   {
                                if (is_array($vv))      {
-                                       foreach($vv as $kkk => $vvv)    {
+                                       foreach ($vv as $kkk => $vvv)   {
                                                if (!is_array($vvv) && $vvv && is_array($this->optValues[substr($kk,0,-1)]))    {
                                                        unset($this->optValues[substr($kk,0,-1)][$kkk]);
                                                }
@@ -418,13 +470,13 @@ class tx_indexedsearch extends tslib_pibase {
                $newSWArr = array();
 
                        // Traverse the search word array:
-               foreach($SWArr as $wordDef)     {
-                       if (!strstr($wordDef['sword'],' '))             {       // No space in word (otherwise it might be a sentense in quotes like "there is").
-                                       // SPlit the search word by lexer:
+               foreach ($SWArr as $wordDef)    {
+                       if (!strstr($wordDef['sword'],' '))     {       // No space in word (otherwise it might be a sentense in quotes like "there is").
+                                       // Split the search word by lexer:
                                $res = $this->lexerObj->split2Words($wordDef['sword']);
 
                                        // Traverse lexer result and add all words again:
-                               foreach($res as $word)  {
+                               foreach ($res as $word) {
                                        $newSWArr[] = array('sword'=>$word, 'oper'=>$wordDef['oper']);
                                }
                        } else {
@@ -458,61 +510,86 @@ class tx_indexedsearch extends tslib_pibase {
         */
        function doSearch($sWArr)       {
 
-                       // Get result rows:
-               $pt1 = t3lib_div::milliseconds();
-               if ($hookObj = &$this->hookRequest('getResultRows'))    {
-                       $resData = $hookObj->getResultRows($sWArr);
-               } else {
-                       $resData = $this->getResultRows($sWArr);
+                       // Find free index uid:
+               $freeIndexUid = $this->piVars['freeIndexUid'];
+               if ($freeIndexUid==-2)  {
+                       $freeIndexUid = $this->conf['search.']['defaultFreeIndexUidList'];
                }
 
-                       // Display search results:
-               $pt2 = t3lib_div::milliseconds();
-               if ($hookObj = &$this->hookRequest('getDisplayResults'))        {
-                       $content = $hookObj->getDisplayResults($sWArr, $resData);
-               } else {
-                       $content = $this->getDisplayResults($sWArr, $resData);
-               }
+               $indexCfgs = t3lib_div::intExplode(',',$freeIndexUid);
+               $accumulatedContent = '';
+
+               foreach ($indexCfgs as $freeIndexUid)   {
+                               // Get result rows:
+                       $pt1 = t3lib_div::milliseconds();
+                       if ($hookObj = &$this->hookRequest('getResultRows'))    {
+                               $resData = $hookObj->getResultRows($sWArr,$freeIndexUid);
+                       } else {
+                               $resData = $this->getResultRows($sWArr,$freeIndexUid);
+                       }
 
-               $pt3 = t3lib_div::milliseconds();
+                               // Display search results:
+                       $pt2 = t3lib_div::milliseconds();
+                       if ($hookObj = &$this->hookRequest('getDisplayResults'))        {
+                               $content = $hookObj->getDisplayResults($sWArr, $resData, $freeIndexUid);
+                       } else {
+                               $content = $this->getDisplayResults($sWArr, $resData, $freeIndexUid);
+                       }
+
+                       $pt3 = t3lib_div::milliseconds();
+
+                               // Create header if we are searching more than one indexing configuration:
+                       if (count($indexCfgs)>1)        {
+                               if ($freeIndexUid>0)    {
+                                       list($indexCfgRec) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('title','index_config','uid='.intval($freeIndexUid).$this->cObj->enableFields('index_config'));
+                                       $titleString = $indexCfgRec['title'];
+                               } else {
+                                       $titleString = $this->pi_getLL('opt_freeIndexUid_header_'.$freeIndexUid);
+                               }
+                               $content = '<h1 class="tx-indexedsearch-category">'.htmlspecialchars($titleString).'</h1>'.$content;
+                       }
+
+                       $accumulatedContent.=$content;
+               }
 
                        // Write search statistics
                $this->writeSearchStat($sWArr,$resData['count'],array($pt1,$pt2,$pt3));
 
                        // Return content:
-               return $content;
+               return $accumulatedContent;
        }
 
        /**
         * Get search result rows / data from database. Returned as data in array.
         *
         * @param       array           Search word array
+        * @param       integer         Pointer to which indexing configuration you want to search in. -1 means no filtering. 0 means only regular indexed content.
         * @return      array           False if no result, otherwise an array with keys for first row, result rows and total number of results found.
         */
-       function getResultRows($sWArr {
+       function getResultRows($sWArr,$freeIndexUid=-1) {
 
                        // Getting SQL result pointer:
                        $GLOBALS['TT']->push('Searching result');
-               $res = $this->getResultRows_SQLpointer($sWArr);
+               $res = $this->getResultRows_SQLpointer($sWArr,$freeIndexUid);
                        $GLOBALS['TT']->pull();
 
                        // Organize and process result:
                if ($res)       {
 
-                               // Get some variables:
-                       $count = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
-                       $pointer = t3lib_div::intInRange($this->piVars['pointer'],0,floor($count/$this->piVars['results']));
+                       $count = $GLOBALS['TYPO3_DB']->sql_num_rows($res);      // Total search-result count
+                       $pointer = t3lib_div::intInRange($this->piVars['pointer'], 0, floor($count/$this->piVars['results']));  // The pointer is set to the result page that is currently being viewed
 
                                // Initialize result accumulation variables:
-                       $c = 0;
-                       $lines = Array();
+                       $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.
+                       $firstRow = array();    // Will hold the first row in result - used to calculate relative hit-ratings.
+                       $resultRows = array();  // Will hold the results rows for display.
+
+                       $exactCount = $this->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.
 
                                // Now, traverse result and put the rows to be displayed into an array
-                               // Each row should be a the fields from 'ISEC.*, IP.*' combined + artificial fields "show_resume" (boolean) and "result_number" (counter)
+                               // 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:
@@ -521,22 +598,27 @@ class tx_indexedsearch extends tslib_pibase {
                                }
 
                                $row['show_resume'] = $this->checkResume($row); // Tells whether we can link directly to a document or not (depends on possible right problems)
+
                                $phashGr = !in_array($row['phash_grouping'], $grouping_phashes);
                                $chashGr = !in_array($row['contentHash'].'.'.$row['data_page_id'], $grouping_chashes);
                                if ($phashGr && $chashGr)       {
-                                       if ($row['show_resume'])        {       // Only if the resume may be shown are we going to filter out duplicates...
+                                       if ($row['show_resume'] || $this->conf['show.']['forbiddenRecords'])    {       // Only if the resume may be shown are we going to filter out duplicates...
                                                if (!$this->multiplePagesType($row['item_type']))       {       // Only on documents which are not multiple pages documents
                                                        $grouping_phashes[] = $row['phash_grouping'];
                                                }
                                                $grouping_chashes[] = $row['contentHash'].'.'.$row['data_page_id'];
-                                       }
-                                       $c++;
 
-                                               // All rows for display is put into resultRows[]
-                                       if ($c > $pointer * $this->piVars['results'])   {
-                                               $row['result_number'] = $c;
-                                               $resultRows[] = $row;
-                                               if ($c+1 > ($pointer+1)*$this->piVars['results'])       break;
+                                               $c++;   // Increase the result pointer
+
+                                                       // All rows for display is put into resultRows[]
+                                               if ($c > $pointer * $this->piVars['results'] && $c <= ($pointer * $this->piVars['results'] + $this->piVars['results'])) {
+                                                       $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 (!$exactCount && (($c+1) > ($pointer+1)*$this->piVars['results']))   { break; }
+                                               }
+                                       } else {
+                                               $count--;       // Skip this row if the user cannot view it (missing permission)
                                        }
                                } else {
                                        $count--;       // 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.
@@ -557,16 +639,20 @@ class tx_indexedsearch extends tslib_pibase {
         * Gets a SQL result pointer to traverse for the search records.
         *
         * @param       array           Search words
+        * @param       integer         Pointer to which indexing configuration you want to search in. -1 means no filtering. 0 means only regular indexed content.
         * @return      pointer
         */
-       function getResultRows_SQLpointer($sWArr      {
+       function getResultRows_SQLpointer($sWArr,$freeIndexUid=-1)      {
                                // This SEARCHES for the searchwords in $sWArr AND returns a COMPLETE list of phash-integers of the matches.
                $list = $this->getPhashList($sWArr);
 
                        // Perform SQL Search / collection of result rows array:
                if ($list)      {
                                // Do the search:
-                       return $this->execFinalQuery($list);
+                       $GLOBALS['TT']->push('execFinalQuery');
+                       $res = $this->execFinalQuery($list,$freeIndexUid);
+                       $GLOBALS['TT']->pull();
+                       return $res;
                } else {
                        return FALSE;
                }
@@ -577,9 +663,10 @@ class tx_indexedsearch extends tslib_pibase {
         *
         * @param       array           Search words array (for display of text describing what was searched for)
         * @param       array           Array with result rows, count, first row.
+        * @param       integer         Pointer to which indexing configuration you want to search in. -1 means no filtering. 0 means only regular indexed content.
         * @return      string          HTML content to display result.
         */
-       function getDisplayResults($sWArr, $resData)    {
+       function getDisplayResults($sWArr, $resData, $freeIndexUid=-1)  {
                        // Perform display of result rows array:
                if ($resData)   {
                        $GLOBALS['TT']->push('Display Final result');
@@ -589,16 +676,16 @@ class tx_indexedsearch extends tslib_pibase {
 
                                // Result display here:
                        $rowcontent = '';
-                       $rowcontent.= $this->compileResult($resData['resultRows']);
+                       $rowcontent.= $this->compileResult($resData['resultRows'], $freeIndexUid);
 
                                // Browsing box:
                        if ($resData['count'])  {
                                $this->internal['res_count'] = $resData['count'];
                                $this->internal['results_at_a_time'] = $this->piVars['results'];
                                $this->internal['maxPages'] = t3lib_div::intInRange($this->conf['search.']['page_links'],1,100,10);
-                               $addString = ($resData['count']&&$this->piVars['group']=='sections' ? ' '.sprintf($this->pi_getLL(count($this->resultSections)>1?'inNsections':'inNsection'),count($this->resultSections)):'');
-                               $browseBox1 = $this->pi_list_browseresults(1,$addString,$this->printResultSectionLinks());
-                               $browseBox2 = $this->pi_list_browseresults(0);
+                               $addString = ($resData['count']&&$this->piVars['group']=='sections'&&$freeIndexUid<=0 ? ' '.sprintf($this->pi_getLL(count($this->resultSections)>1?'inNsections':'inNsection'),count($this->resultSections)):'');
+                               $browseBox1 = $this->pi_list_browseresults(1,$addString,$this->printResultSectionLinks(),$freeIndexUid);
+                               $browseBox2 = $this->pi_list_browseresults(0,'','',$freeIndexUid);
                        }
 
                                // Browsing nav, bottom.
@@ -616,7 +703,7 @@ class tx_indexedsearch extends tslib_pibase {
                        // Print a message telling which words we searched for, and in which sections etc.
                $what = $this->tellUsWhatIsSeachedFor($sWArr).
                                (substr($this->piVars['sections'],0,2)=='rl'?' '.$this->pi_getLL('inSection','',1).' "'.substr($this->getPathFromPageId(substr($this->piVars['sections'],4)),1).'"':'');
-               $what = '<div'.$this->pi_classParam('whatis').'><p>'.$what.'</p></div>';
+               $what = '<div'.$this->pi_classParam('whatis').'>'.$this->cObj->stdWrap($what, $this->conf['whatis_stdWrap.']).'</div>';
                $content = $what.$content;
 
                        // Return content:
@@ -628,14 +715,15 @@ class tx_indexedsearch extends tslib_pibase {
         * Takes the "group" var into account: Makes a "section" or "flat" display.
         *
         * @param       array           Result rows
+        * @param       integer         Pointer to which indexing configuration you want to search in. -1 means no filtering. 0 means only regular indexed content.
         * @return      string          HTML
         */
-       function compileResult($resultRows)     {
+       function compileResult($resultRows, $freeIndexUid=-1)   {
                $content = '';
 
                        // Transfer result rows to new variable, performing some mapping of sub-results etc.
                $newResultRows = array();
-               foreach($resultRows as $row)    {
+               foreach ($resultRows as $row)   {
                        $id = md5($row['phash_grouping']);
                        if (is_array($newResultRows[$id]))      {
                                if (!$newResultRows[$id]['show_resume'] && $row['show_resume']) {       // swapping:
@@ -654,49 +742,58 @@ class tx_indexedsearch extends tslib_pibase {
                        }
                }
                $resultRows = $newResultRows;
+               $this->resultSections = array();
 
+               if ($freeIndexUid<=0)   {
+                       switch($this->piVars['group'])  {
+                               case 'sections':
 
-               switch($this->piVars['group'])  {
-                       case 'sections':
+                                       $rl2flag = substr($this->piVars['sections'],0,2)=='rl';
+                                       $sections = array();
+                                       foreach ($resultRows as $row)   {
+                                               $id = $row['rl0'].'-'.$row['rl1'].($rl2flag?'-'.$row['rl2']:'');
+                                               $sections[$id][] = $row;
+                                       }
 
-                               $rl2flag = substr($this->piVars['sections'],0,2)=='rl';
-                               $sections = array();
-                               foreach($resultRows as $row)    {
-                                       $id = $row['rl0'].'-'.$row['rl1'].($rl2flag?'-'.$row['rl2']:'');
-                                       $sections[$id][] = $row;
-                               }
+                                       $this->resultSections = array();
 
-                               $this->resultSections = array();
+                                       foreach ($sections as $id => $resultRows)       {
+                                               $rlParts = explode('-',$id);
+                                               $theId = $rlParts[2] ? $rlParts[2] : ($rlParts[1]?$rlParts[1]:$rlParts[0]);
+                                               $theRLid = $rlParts[2] ? 'rl2_'.$rlParts[2]:($rlParts[1]?'rl1_'.$rlParts[1]:'0');
 
-                               foreach($sections as $id => $resultRows)        {
-                                       $rlParts = explode('-',$id);
-                                       $theId = $rlParts[2] ? $rlParts[2] : ($rlParts[1]?$rlParts[1]:$rlParts[0]);
-                                       $theRLid = $rlParts[2] ? 'rl2_'.$rlParts[2]:($rlParts[1]?'rl1_'.$rlParts[1]:'0');
+                                               $sectionName = $this->getPathFromPageId($theId);
+                                               if ($sectionName{0} == '/') $sectionName = substr($sectionName,1);
 
-                                       $sectionName = substr($this->getPathFromPageId($theId),1);
-                                       if (!trim($sectionName))        {
-                                               $sectionTitleLinked = $this->pi_getLL('unnamedSection','',1).':';
-                                       } 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));
+                                               if (!trim($sectionName))        {
+                                                       $sectionTitleLinked = $this->pi_getLL('unnamedSection','',1).':';
+                                               } 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 content header:
-                                       $content.= $this->makeSectionHeader($id,$sectionTitleLinked,count($resultRows));
+                                                       // Add content header:
+                                               $content.= $this->makeSectionHeader($id,$sectionTitleLinked,count($resultRows));
 
-                                               // Render result rows:
-                                       foreach($resultRows as $row)    {
+                                                       // Render result rows:
+                                               foreach ($resultRows as $row)   {
+                                                       $content.= $this->printResultRow($row);
+                                               }
+                                       }
+                               break;
+                               default:        // flat:
+                                       foreach ($resultRows as $row)   {
                                                $content.= $this->printResultRow($row);
                                        }
-                               }
-                       break;
-                       default:        // flat:
-                               foreach($resultRows as $row)    {
-                                       $content.= $this->printResultRow($row);
-                               }
-                       break;
+                               break;
+                       }
+               } else {
+                       foreach ($resultRows as $row)   {
+                               $content.= $this->printResultRow($row);
+                       }
                }
+
                return '<div'.$this->pi_classParam('res').'>'.$content.'</div>';
        }
 
@@ -731,36 +828,36 @@ class tx_indexedsearch extends tslib_pibase {
                $this->wSelClauses = array();
 
                        // Traverse searchwords; for each, select all phash integers and merge/diff/intersect them with previous word (based on operator)
-               foreach($sWArr as $k => $v)     {
-                       $GLOBALS['TT']->push('SearchWord '.$sWord);
-
+               foreach ($sWArr 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->piVars['type'];
                        if (strstr($sWord,' ')) $theType = 20;  // If there are spaces in the search-word, make a full text search instead.
+
+                       $GLOBALS['TT']->push('SearchWord "'.$sWord.'" - $theType='.$theType);
+
                        $res = '';
                        $wSel='';
 
                                // Perform search for word:
                        switch($theType)        {
-                               case '1':
+                               case '1':       // Part of word
                                        $wSel = "IW.baseword LIKE '%".$GLOBALS['TYPO3_DB']->quoteStr($sWord, 'index_words')."%'";
                                        $res = $this->execPHashListQuery($wSel,' AND is_stopword=0');
                                break;
-                               case '2':
+                               case '2':       // First part of word
                                        $wSel = "IW.baseword LIKE '".$GLOBALS['TYPO3_DB']->quoteStr($sWord, 'index_words')."%'";
                                        $res = $this->execPHashListQuery($wSel,' AND is_stopword=0');
                                break;
-                               case '3':
+                               case '3':       // Last part of word
                                        $wSel = "IW.baseword LIKE '%".$GLOBALS['TYPO3_DB']->quoteStr($sWord, 'index_words')."'";
                                        $res = $this->execPHashListQuery($wSel,' AND is_stopword=0');
                                break;
-                               case '10':
+                               case '10':      // Sounds like
                                        $wSel = 'IW.metaphone = '.$this->indexerObj->metaphone($sWord);
                                        $res = $this->execPHashListQuery($wSel,' AND is_stopword=0');
                                break;
-                               case '20':
+                               case '20':      // Sentence
                                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
                                                                'ISEC.phash',
                                                                'index_section ISEC, index_fulltext IFT',
@@ -773,7 +870,7 @@ class tx_indexedsearch extends tslib_pibase {
 
                                        if ($this->piVars['type']==20)  $this->piVars['order'] = 'mtime';               // 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 instaed. It is not required, but otherwise some hits may be left out.
                                break;
-                               default:
+                               default:        // Distinct word
                                        $wSel = 'IW.wid = '.$hash = $this->indexerObj->md5inthash($sWord);
                                        $res = $this->execPHashListQuery($wSel,' AND is_stopword=0');
                                break;
@@ -858,7 +955,7 @@ class tx_indexedsearch extends tslib_pibase {
                        $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)  {
+                       foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['addRootLineFields'] as $fieldName => $rootLineLevel) {
                                if (substr($this->piVars['sections'],0,strlen($fieldName)+1)==$fieldName.'_')   {
                                        $list = implode(',',t3lib_div::intExplode(',',substr($this->piVars['sections'],strlen($fieldName)+1)));
                                        $out.= 'AND ISEC.'.$fieldName.' IN ('.$list.')';
@@ -923,17 +1020,61 @@ class tx_indexedsearch extends tslib_pibase {
        }
 
        /**
+        * Where-clause for free index-uid value.
+        *
+        * @param       integer         Free Index UID value to limit search to.
+        * @return      string          WHERE SQL clause part.
+        */
+       function freeIndexUidWhere($freeIndexUid)       {
+
+               if ($freeIndexUid>=0)   {
+
+                               // First, look if the freeIndexUid is a meta configuration:
+                       list($indexCfgRec) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('indexcfgs','index_config','type=5 AND uid='.intval($freeIndexUid).$this->cObj->enableFields('index_config'));
+                       if (is_array($indexCfgRec))     {
+                               $refs = t3lib_div::trimExplode(',',$indexCfgRec['indexcfgs']);
+                               $list = array(-99);     // Default value to protect against empty array.
+                               foreach ($refs as $ref) {
+                                       list($table,$uid) = t3lib_div::revExplode('_',$ref,2);
+                                       switch ($table) {
+                                               case 'index_config':
+                                                       list($idxRec) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid','index_config','uid='.intval($uid).$this->cObj->enableFields('index_config'));
+                                                       if ($idxRec)    $list[] = $uid;
+                                               break;
+                                               case 'pages':
+                                                       $indexCfgRecordsFromPid = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid','index_config','pid='.intval($uid).$this->cObj->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
         */
-       function execFinalQuery($list {
+       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);
@@ -1022,12 +1163,13 @@ class tx_indexedsearch extends tslib_pibase {
                                                $wordSel.'
                                                        IP.phash IN ('.$list.') '.
                                                        $this->mediaTypeWhere().' '.
-                                                       $this->languageWhere().'
+                                                       $this->languageWhere().
+                                                       $freeIndexUidClause.'
                                                        AND IW.wid=IR.wid
                                                        AND ISEC.phash = IR.phash
                                                        AND IP.phash = IR.phash
                                                        AND     '.$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.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:
@@ -1050,10 +1192,11 @@ class tx_indexedsearch extends tslib_pibase {
                                                'index_phash IP,index_section ISEC'.$page_join,
                                                'IP.phash IN ('.$list.') '.
                                                        $this->mediaTypeWhere().' '.
-                                                       $this->languageWhere().'
+                                                       $this->languageWhere().
+                                                       $freeIndexUidClause.'
                                                        AND IP.phash = ISEC.phash
                                                        AND '.$page_where,
-                                               'IP.phash',
+                                               '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
                                        );
                }
@@ -1142,11 +1285,12 @@ class tx_indexedsearch extends tslib_pibase {
                $newId = $GLOBALS['TYPO3_DB']->sql_insert_id();
 
                if ($newId)     {
-                       foreach($sWArr as $val) {
+                       foreach ($sWArr as $val)        {
                                $insertFields = array(
                                        'word' => $val['sword'],                // $GLOBALS['TSFE']->csConvObj->conv_case('utf-8', $val['sword'], 'toLower'),
                                        'index_stat_search_id' => $newId,
-                                       'tstamp' => $GLOBALS['EXEC_TIME']               // Time stamp
+                                       'tstamp' => $GLOBALS['EXEC_TIME'],              // Time stamp
+                                       'pageid' => $GLOBALS['TSFE']->id        //search page id for indexed search stats
                                );
 
                                $GLOBALS['TYPO3_DB']->exec_INSERTquery('index_stat_word', $insertFields);
@@ -1179,70 +1323,171 @@ class tx_indexedsearch extends tslib_pibase {
         * @return      string          Search form HTML
         */
        function makeSearchForm($optValues)     {
+               $html = $this->cObj->getSubpart($this->templateCode, '###SEARCH_FORM###');
+
+                       // Multilangual text
+               $substituteArray = array('searchFor', 'extResume', 'atATime', 'orderBy', 'fromSection', 'searchIn', 'match', 'style', 'freeIndexUid');
+               foreach ($substituteArray as $marker)   {
+                       $markerArray['###FORM_'.t3lib_div::strtoupper($marker).'###'] = $this->pi_getLL('form_'.$marker,'',1);
+               }
 
-                       // Accumulate table rows here:
-               $rows = array();
+               $markerArray['###FORM_SUBMIT###'] = $this->pi_getLL('submit_button_label','',1);
 
-                       // Adding search field and button:
-               $rows[]='<tr>
-                               <td nowrap="nowrap"><p>'.$this->pi_getLL('form_searchFor','',1).'&nbsp;</p></td>
-                               <td><input type="text" name="'.$this->prefixId.'[sword]" value="'.htmlspecialchars($this->conf['show.']['clearSearchBox']?'':$this->piVars['sword']).'"'.$this->pi_classParam('searchbox-sword').' />&nbsp;&nbsp;<input type="submit" name="'.$this->prefixId.'[submit_button]" value="'.$this->pi_getLL('submit_button_label','',1).'"'.$this->pi_classParam('searchbox-button').' /></td>
-                       </tr>';
+                       // Adding search field value
+               $markerArray['###SWORD_VALUE###'] = htmlspecialchars($this->piVars['sword']);
 
+                       // Additonal keyword => "Add to current search words"
                if ($this->conf['show.']['clearSearchBox'] && $this->conf['show.']['clearSearchBox.']['enableSubSearchCheckBox'])       {
-                       $rows[]='<tr>
-                               <td></td>
-                               <td><input type="hidden" name="'.$this->prefixId.'[sword_prev]" value="'.htmlspecialchars($this->piVars['sword']).'" /><input type="checkbox" name="'.$this->prefixId.'[sword_prev_include]" value="1"'.($this->piVars['sword_prev_include']?' checked="checked"':'').' /> '.$this->pi_getLL('makerating_addToCurrentSearch').'</td>
-                       </tr>';
+                       $markerArray['###SWORD_PREV_VALUE###'] = htmlspecialchars($this->conf['show.']['clearSearchBox'] ? '' : $this->piVars['sword']);
+                       $markerArray['###SWORD_PREV_INCLUDE_CHECKED###'] = $this->piVars['sword_prev_include'] ? ' checked="checked"':'';
+                       $markerArray['###ADD_TO_CURRENT_SEARCH###'] = $this->pi_getLL('makerating_addToCurrentSearch','',1);
+               } else {
+                       $html = $this->cObj->substituteSubpart($html, '###ADDITONAL_KEYWORD###', '');
+               }
+
+               $markerArray['###ACTION_URL###'] = htmlspecialchars($this->pi_getPageLink($GLOBALS['TSFE']->id, $GLOBALS['TSFE']->sPre));
+
+               $hiddenFieldCode = $this->cObj->getSubpart($this->templateCode, '###HIDDEN_FIELDS###');
+               $hiddenFieldCode = preg_replace('/^\n\t(.+)/ms', '$1', $hiddenFieldCode);               // Remove first newline and tab (cosmetical issue)
+               $hiddenFieldArr = array();
+
+               foreach (t3lib_div::trimExplode(',',$this->hiddenFieldList) as $fieldName)      {
+                       $hiddenFieldMarkerArray = array();
+                       $hiddenFieldMarkerArray['###HIDDEN_FIELDNAME###'] = $this->prefixId.'['.$fieldName.']';
+                       $hiddenFieldMarkerArray['###HIDDEN_VALUE###'] = htmlspecialchars((string)$this->piVars[$fieldName]);
+
+                       $hiddenFieldArr[$fieldName] = $this->cObj->substituteMarkerArrayCached($hiddenFieldCode, $hiddenFieldMarkerArray, array(), array());
                }
 
-                       // Extended search options:
+                       // Extended search
                if ($this->piVars['ext'])       {
-                       if (is_array($optValues['type']) || is_array($optValues['defOp']))      $rows[]='<tr>
-                                       <td nowrap="nowrap"><p>'.$this->pi_getLL('form_match','',1).'&nbsp;</p></td>
-                                       <td>'.$this->renderSelectBox($this->prefixId.'[type]',$this->piVars['type'],$optValues['type']).
-                                       $this->renderSelectBox($this->prefixId.'[defOp]',$this->piVars['defOp'],$optValues['defOp']).'</td>
-                               </tr>';
-                       if (is_array($optValues['media']) || is_array($optValues['lang']))      $rows[]='<tr>
-                                       <td nowrap="nowrap"><p>'.$this->pi_getLL('form_searchIn','',1).'&nbsp;</p></td>
-                                       <td>'.$this->renderSelectBox($this->prefixId.'[media]',$this->piVars['media'],$optValues['media']).
-                                       $this->renderSelectBox($this->prefixId.'[lang]',$this->piVars['lang'],$optValues['lang']).'</td>
-                               </tr>';
-                       if (is_array($optValues['sections']))   $rows[]='<tr>
-                                       <td nowrap="nowrap"><p>'.$this->pi_getLL('form_fromSection','',1).'&nbsp;</p></td>
-                                       <td>'.$this->renderSelectBox($this->prefixId.'[sections]',$this->piVars['sections'],$optValues['sections']).'</td>
-                               </tr>';
-                       if (is_array($optValues['order']) || is_array($optValues['desc']) || is_array($optValues['results']))   $rows[]='<tr>
-                                       <td nowrap="nowrap"><p>'.$this->pi_getLL('form_orderBy','',1).'&nbsp;</p></td>
-                                       <td><p>'.$this->renderSelectBox($this->prefixId.'[order]',$this->piVars['order'],$optValues['order']).
-                                               $this->renderSelectBox($this->prefixId.'[desc]',$this->piVars['desc'],$optValues['desc']).
-                                               $this->renderSelectBox($this->prefixId.'[results]',$this->piVars['results'],$optValues['results']).'&nbsp;'.$this->pi_getLL('form_atATime','',1).'</p></td>
-                               </tr>';
-                       if (is_array($optValues['group']) || !$this->conf['blind.']['extResume'])       $rows[]='<tr>
-                                       <td nowrap="nowrap"><p>'.$this->pi_getLL('form_style','',1).'&nbsp;</p></td>
-                                       <td><p>'.$this->renderSelectBox($this->prefixId.'[group]',$this->piVars['group'],$optValues['group']).
-                                       (!$this->conf['blind.']['extResume'] ? '&nbsp; &nbsp;
-                                       <input type="hidden" name="'.$this->prefixId.'[extResume]" value="0" /><input type="checkbox" value="1" name="'.$this->prefixId.'[extResume]"'.($this->piVars['extResume']?' checked="checked"':'').' />'.$this->pi_getLL('form_extResume','',1):'').'</p></td>
-                               </tr>';
-               }
-
-                       // Compile rows into a table, wrapped in form-tags:
-               $out='
-                       <form action="'.htmlspecialchars($this->pi_getPageLink($GLOBALS['TSFE']->id,$GLOBALS['TSFE']->sPre)).'" method="post" name="'.$this->prefixId.'" style="margin: 0 0 0 0;">
-                               <table '.$this->conf['tableParams.']['searchBox'].'>
-                               '.implode(chr(10),$rows).'
-                               </table>
-                               <input type="hidden" name="'.$this->prefixId.'[_sections]" value="0" />
-                               <input type="hidden" name="'.$this->prefixId.'[pointer]" value="0" />
-                               <input type="hidden" name="'.$this->prefixId.'[ext]" value="'.($this->piVars['ext']?1:0).'" />
-                       </form>';
-               $out.='<p>'.
-                               ($this->piVars['ext'] ?
-                                       '<a href="'.htmlspecialchars($this->pi_getPageLink($GLOBALS['TSFE']->id,$GLOBALS['TSFE']->sPre,array($this->prefixId.'[ext]'=>0))).'">'.$this->pi_getLL('link_regularSearch','',1).'</a>' :
-                                       '<a href="'.htmlspecialchars($this->pi_getPageLink($GLOBALS['TSFE']->id,$GLOBALS['TSFE']->sPre,array($this->prefixId.'[ext]'=>1))).'">'.$this->pi_getLL('link_advancedSearch','',1).'</a>'
-                               ).'</p>';
-
-               return '<div'.$this->pi_classParam('searchbox').'>'.$out.'</div>';
+
+                               // Search for
+                       if ((!is_array($optValues['type']) && !is_array($optValues['defOp'])) || ($this->conf['blind.']['type'] && $this->conf['blind.']['defOp']))     {
+                               $html = $this->cObj->substituteSubpart($html, '###SELECT_SEARCH_FOR###', '');
+                       } else {
+                               if (is_array($optValues['type']) && !$this->conf['blind.']['type'])     {
+                                       unset($hiddenFieldArr['type']);
+                                       $markerArray['###SELECTBOX_TYPE_VALUES###'] = $this->renderSelectBoxValues($this->piVars['type'],$optValues['type']);
+                               } else {
+                                       $html = $this->cObj->substituteSubpart($html, '###SELECT_SEARCH_TYPE###', '');
+                               }
+
+                               if (is_array($optValues['defOp']) || !$this->conf['blind.']['defOp'])   {
+                                       $markerArray['###SELECTBOX_DEFOP_VALUES###'] = $this->renderSelectBoxValues($this->piVars['defOp'],$optValues['defOp']);
+                               } else {
+                                       $html = $this->cObj->substituteSubpart($html, '###SELECT_SEARCH_DEFOP###', '');
+                               }
+                       }
+
+                               // Search in
+                       if ((!is_array($optValues['media']) && !is_array($optValues['lang'])) || ($this->conf['blind.']['media'] && $this->conf['blind.']['lang']))     {
+                               $html = $this->cObj->substituteSubpart($html, '###SELECT_SEARCH_IN###', '');
+                       } else {
+                               if (is_array($optValues['media']) && !$this->conf['blind.']['media'])   {
+                                       unset($hiddenFieldArr['media']);
+                                       $markerArray['###SELECTBOX_MEDIA_VALUES###'] = $this->renderSelectBoxValues($this->piVars['media'],$optValues['media']);
+                               } else {
+                                       $html = $this->cObj->substituteSubpart($html, '###SELECT_SEARCH_MEDIA###', '');
+                               }
+
+                               if (is_array($optValues['lang']) || !$this->conf['blind.']['lang'])     {
+                                       unset($hiddenFieldArr['lang']);
+                                       $markerArray['###SELECTBOX_LANG_VALUES###'] = $this->renderSelectBoxValues($this->piVars['lang'],$optValues['lang']);
+                               } else {
+                                       $html = $this->cObj->substituteSubpart($html, '###SELECT_SEARCH_LANG###', '');
+                               }
+                       }
+
+                               // Sections
+                       if (!is_array($optValues['sections']) || $this->conf['blind.']['sections'])     {
+                               $html = $this->cObj->substituteSubpart($html, '###SELECT_SECTION###', '');
+                       } else {
+                               $markerArray['###SELECTBOX_SECTIONS_VALUES###'] = $this->renderSelectBoxValues($this->piVars['sections'],$optValues['sections']);
+                       }
+
+                               // Free Indexing Configurations:
+                       if (!is_array($optValues['freeIndexUid']) || $this->conf['blind.']['freeIndexUid'])     {
+                               $html = $this->cObj->substituteSubpart($html, '###SELECT_FREEINDEXUID###', '');
+                       } else {
+                               $markerArray['###SELECTBOX_FREEINDEXUIDS_VALUES###'] = $this->renderSelectBoxValues($this->piVars['freeIndexUid'],$optValues['freeIndexUid']);
+                       }
+
+                               // Sorting
+                       if (!is_array($optValues['order']) || !is_array($optValues['desc']) || $this->conf['blind.']['order'])  {
+                               $html = $this->cObj->substituteSubpart($html, '###SELECT_ORDER###', '');
+                       } else {
+                               unset($hiddenFieldArr['order']);
+                               unset($hiddenFieldArr['desc']);
+                               unset($hiddenFieldArr['results']);
+                               $markerArray['###SELECTBOX_ORDER_VALUES###'] = $this->renderSelectBoxValues($this->piVars['order'],$optValues['order']);
+                               $markerArray['###SELECTBOX_DESC_VALUES###'] = $this->renderSelectBoxValues($this->piVars['desc'],$optValues['desc']);
+                               $markerArray['###SELECTBOX_RESULTS_VALUES###'] = $this->renderSelectBoxValues($this->piVars['results'],$optValues['results']);
+                       }
+
+                               // Limits
+                       if (!is_array($optValues['results']) || !is_array($optValues['results']) || $this->conf['blind.']['results'])   {
+                               $html = $this->cObj->substituteSubpart($html, '###SELECT_RESULTS###', '');
+                       } else {
+                               $markerArray['###SELECTBOX_RESULTS_VALUES###'] = $this->renderSelectBoxValues($this->piVars['results'],$optValues['results']);
+                       }
+
+                               // Grouping
+                       if (!is_array($optValues['group']) || $this->conf['blind.']['group'])   {
+                               $html = $this->cObj->substituteSubpart($html, '###SELECT_GROUP###', '');
+                       } else {
+                               unset($hiddenFieldArr['group']);
+                               $markerArray['###SELECTBOX_GROUP_VALUES###'] = $this->renderSelectBoxValues($this->piVars['group'],$optValues['group']);
+                       }
+
+                       if ($this->conf['blind.']['extResume']) {
+                               $html = $this->cObj->substituteSubpart($html, '###SELECT_EXTRESUME###', '');
+                       } else {
+                               $markerArray['###EXT_RESUME_CHECKED###'] = $this->piVars['extResume'] ? ' checked="checked"' : '';
+                       }
+
+               } else {        // Extended search
+                       $html = $this->cObj->substituteSubpart($html, '###SEARCH_FORM_EXTENDED###', '');
+               }
+
+               if($this->conf['show.']['advancedSearchLink'])  {
+                       $linkToOtherMode = ($this->piVars['ext'] ?
+                               $this->pi_getPageLink($GLOBALS['TSFE']->id,$GLOBALS['TSFE']->sPre,array($this->prefixId.'[ext]'=>0)) :
+                               $this->pi_getPageLink($GLOBALS['TSFE']->id,$GLOBALS['TSFE']->sPre,array($this->prefixId.'[ext]'=>1))
+                       );
+
+                       $markerArray['###LINKTOOTHERMODE###'] = '<a href="'.htmlspecialchars($linkToOtherMode).'">'.$this->pi_getLL($this->piVars['ext']?'link_regularSearch':'link_advancedSearch', '', 1).'</a>';
+               } else {
+                       $markerArray['###LINKTOOTHERMODE###'] = '';
+               }
+
+                       // Write all hidden fields
+               $html = $this->cObj->substituteSubpart($html, '###HIDDEN_FIELDS###', implode('',$hiddenFieldArr));
+
+               $substitutedContent = $this->cObj->substituteMarkerArrayCached($html, $markerArray, array(), array());
+
+               return $substitutedContent;
+       }
+
+       /**
+        * Function, rendering selector box values.
+        *
+        * @param       string          Current value
+        * @param       array           Array with the options as key=>value pairs
+        * @return      string          <options> imploded.
+        */
+       function renderSelectBoxValues($value,$optValues)       {
+               if (is_array($optValues))       {
+                       $opt=array();
+                       $isSelFlag=0;
+                       foreach ($optValues as $k=>$v)  {
+                               $sel = (!strcmp($k,$value) ? ' selected="selected"' : '');
+                               if ($sel)       { $isSelFlag++; }
+                               $opt[]='<option value="'.htmlspecialchars($k).'"'.$sel.'>'.htmlspecialchars($v).'</option>';
+                       }
+
+                       return implode('',$opt);
+               }
        }
 
        /**
@@ -1251,14 +1496,17 @@ class tx_indexedsearch extends tslib_pibase {
         * @return      string          Rules for the search
         */
        function printRules()   {
-               $out = '';
                if ($this->conf['show.']['rules'])      {
-                       $out = '<h2>'.$this->pi_getLL('rules_header','',1).'</h2>
-                                       <p>'.nl2br(trim($this->pi_getLL('rules_text','',1))).'</p>';
-                       $out = '
-                                       <div'.$this->pi_classParam('rules').'>'.$this->cObj->stdWrap($out, $this->conf['rules_stdWrap.']).'</div>';
+
+                       $html = $this->cObj->getSubpart($this->templateCode, '###RULES###');
+
+                       $markerArray['###RULES_HEADER###'] = $this->pi_getLL('rules_header','',1);
+                       $markerArray['###RULES_TEXT###'] = nl2br(trim($this->pi_getLL('rules_text','',1)));
+
+                       $substitutedContent = $this->cObj->substituteMarkerArrayCached($html, $markerArray, array(), array());
+
+                       return '<div'.$this->pi_classParam('rules').'>'.$this->cObj->stdWrap($substitutedContent, $this->conf['rules_stdWrap.']).'</div>';
                }
-               return $out;
        }
 
        /**
@@ -1270,13 +1518,25 @@ class tx_indexedsearch extends tslib_pibase {
                if (count($this->resultSections))       {
                        $lines = array();
 
-                       foreach($this->resultSections as $id => $dat)   {
-                               $lines[] = '<li><a href="'.htmlspecialchars($GLOBALS['TSFE']->anchorPrefix.'#'.md5($id)).'">'.
-                                                       htmlspecialchars(trim($dat[0])?trim($dat[0]):$this->pi_getLL('unnamedSection')).' ('.$dat[1].' '.$this->pi_getLL($dat[1]>1?'word_pages':'word_page','',1).')'.
-                                                       '</a></li>';
+                       $html = $this->cObj->getSubpart($this->templateCode, '###RESULT_SECTION_LINKS###');
+                       $item = $this->cObj->getSubpart($this->templateCode, '###RESULT_SECTION_LINKS_LINK###');
+
+                       foreach ($this->resultSections as $id => $dat)  {
+                               $markerArray = array();
+
+                               $aBegin = '<a href="'.htmlspecialchars($GLOBALS['TSFE']->anchorPrefix.'#anchor_'.md5($id)).'">';
+                               $aContent = htmlspecialchars(trim($dat[0]) ? trim($dat[0]) : $this->pi_getLL('unnamedSection')).
+                                               ' ('.$dat[1].' '.$this->pi_getLL($dat[1]>1 ? 'word_pages' : 'word_page','',1).')';
+                               $aEnd = '</a>';
+
+                               $markerArray['###LINK###'] = $aBegin . $aContent . $aEnd;
+
+                               $links[] = $this->cObj->substituteMarkerArrayCached($item, $markerArray, array(), array());
                        }
-                       $out = '<ul>'.implode(chr(10),$lines).'</ul>';
-                       return '<div'.$this->pi_classParam('sectionlinks').'>'.$this->cObj->stdWrap($out, $this->conf['sectionlinks_stdWrap.']).'</div>';
+
+                       $html = $this->cObj->substituteMarkerArrayCached($html, array('###LINKS###' => implode('',$links)), array(), array());
+
+                       return '<div'.$this->pi_classParam('sectionlinks').'>'.$this->cObj->stdWrap($html, $this->conf['sectionlinks_stdWrap.']).'</div>';
                }
        }
 
@@ -1288,13 +1548,18 @@ class tx_indexedsearch extends tslib_pibase {
         * @param       integer         Number of results in section
         * @return      string          HTML output
         */
-       function makeSectionHeader($id,$sectionTitleLinked,$countResultRows)    {
-               return '<div'.$this->pi_classParam('secHead').'><a name="'.md5($id).'"></a><table '.$this->conf['tableParams.']['secHead'].'>
-                                               <tr>
-                                               <td width="95%"><h2>'.$sectionTitleLinked.'</h2></td>
-                                               <td align="right" nowrap="nowrap"><p>'.$countResultRows.' '.$this->pi_getLL($countResultRows>1?'word_pages':'word_page','',1).'</p></td>
-                                               </tr>
-                                       </table></div>';
+       function makeSectionHeader($id, $sectionTitleLinked, $countResultRows)  {
+
+               $html = $this->cObj->getSubpart($this->templateCode, '###SECTION_HEADER###');
+
+               $markerArray['###ANCHOR_URL###'] = 'anchor_'.md5($id);
+               $markerArray['###SECTION_TITLE###'] = $sectionTitleLinked;
+               $markerArray['###RESULT_COUNT###'] = $countResultRows;
+               $markerArray['###RESULT_NAME###'] = $this->pi_getLL('word_page'.($countResultRows>1 ? 's' : ''));
+
+               $substitutedContent = $this->cObj->substituteMarkerArrayCached($html, $markerArray, array(), array());
+
+               return $substitutedContent;
        }
 
        /**
@@ -1313,61 +1578,54 @@ class tx_indexedsearch extends tslib_pibase {
                        return $hookObj->printResultRow($row, $headerOnly, $tmplContent);
                } else {
 
-                               // Make the header row with title, icon and rating bar.:
-                       $out.='<tr '.$this->pi_classParam('title'.$tmplContent['CSSsuffix']).'>
-                               <td width="16">'.$tmplContent['icon'].'</td>
-                               <td width="95%" nowrap="nowrap"><p>'.
-                                       #$row['phash'].' // '.
-                                       $tmplContent['result_number'].': '.
-                                       $tmplContent['title'].
-                                       '</p></td>
-                               <td nowrap="nowrap"><p'.$this->pi_classParam('percent'.$tmplContent['CSSsuffix']).'>'.$tmplContent['rating'].'</p></td>
-                       </tr>';
-
-                               // Print the resume-section. If headerOnly is 1, then  only the short resume is printed
+                       $html = $this->cObj->getSubpart($this->templateCode, '###RESULT_OUTPUT###');
+
+                       if (!is_array($row['_sub']))    {
+                               $html = $this->cObj->substituteSubpart($html, '###ROW_SUB###', '');
+                       }
+
                        if (!$headerOnly)       {
-                               $out.='<tr>
-                                       <td></td>
-                                       <td colspan="2"'.$this->pi_classParam('descr'.$tmplContent['CSSsuffix']).'><p>'.$tmplContent['description'].'</p></td>
-                               </tr>';
-                               $out.='<tr>
-                                       <td></td>
-                                       <td '.$this->pi_classParam('info'.$tmplContent['CSSsuffix']).' nowrap="nowrap"><p>'.
-                                               $tmplContent['size'].' - '.$tmplContent['created'].' - '.$tmplContent['modified'].
-                                               ($tmplContent['path'] ? '<br/>'.$this->pi_getLL('res_path','',1).' '.$tmplContent['path'] : '').
-                                               '</p></td>
-                                       <td '.$this->pi_classParam('info'.$tmplContent['CSSsuffix']).' align="right"><p>'.$tmplContent['access'].$tmplContent['language'].'</p></td>
-                               </tr>';
+                               $html = $this->cObj->substituteSubpart($html, '###ROW_SHORT###', '');
+
                        } elseif ($headerOnly==1) {
-                               $out.='<tr>
-                                       <td></td>
-                                       <td colspan="2"'.$this->pi_classParam('descr'.$tmplContent['CSSsuffix']).'><p>'.$tmplContent['description'].'</p></td>
-                               </tr>';
+                               $html = $this->cObj->substituteSubpart($html, '###ROW_LONG###', '');
+                       } elseif ($headerOnly==2) {
+                               $html = $this->cObj->substituteSubpart($html, '###ROW_SHORT###', '');
+                               $html = $this->cObj->substituteSubpart($html, '###ROW_LONG###', '');
                        }
 
+                       if (is_array($tmplContent))     {
+                               foreach ($tmplContent AS $k => $v)      {
+                                       $markerArray['###'.t3lib_div::strtoupper($k).'###'] = $v;
+                               }
+                       }
+
+                               // Description text
+                       $markerArray['###TEXT_ITEM_SIZE###'] = $this->pi_getLL('res_size','',1);
+                       $markerArray['###TEXT_ITEM_CRDATE###'] = $this->pi_getLL('res_created','',1);
+                       $markerArray['###TEXT_ITEM_MTIME###'] = $this->pi_getLL('res_modified','',1);
+                       $markerArray['###TEXT_ITEM_PATH###'] = $this->pi_getLL('res_path','',1);
+
+                       $html = $this->cObj->substituteMarkerArrayCached($html, $markerArray, array(), array());
+
                                // 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']))     {
                                if ($this->multiplePagesType($row['item_type']))        {
-                                       $out.='<tr>
-                                               <td></td>
-                                               <td colspan="2"><p><br/>'.$this->pi_getLL('res_otherMatching','',1).'<br/><br/></p></td>
-                                       </tr>';
-
-                                       foreach($row['_sub'] as $subRow)        {
-                                               $out.='<tr>
-                                                       <td></td>
-                                                       <td colspan="2"><p>'.$this->printResultRow($subRow,1).'</p></td>
-                                               </tr>';
+
+                                       $html = str_replace('###TEXT_ROW_SUB###', $this->pi_getLL('res_otherMatching','',1), $html);
+
+                                       foreach ($row['_sub'] as $subRow)       {
+                                               $html .= $this->printResultRow($subRow,1);
                                        }
                                } else {
-                                       $out.='<tr>
-                                               <td></td>
-                                               <td colspan="2"><p>'.$this->pi_getLL('res_otherPageAsWell','',1).'</p></td>
-                                       </tr>';
+
+                                       $markerArray['###TEXT_ROW_SUB###'] = $this->pi_getLL('res_otherMatching','',1);
+
+                                       $html = str_replace('###TEXT_ROW_SUB###', $this->pi_getLL('res_otherPageAsWell','',1), $html);
                                }
                        }
 
-                       return '<table '.$this->conf['tableParams.']['searchRes'].'>'.$out.'</table><br/>';
+                       return $html;
                }
        }
 
@@ -1377,43 +1635,69 @@ class tx_indexedsearch extends tslib_pibase {
         * @param       boolean         Show result count
         * @param       string          String appended to "displaying results..." notice.
         * @param       string          String appended after section "displaying results..."
+        * @param       string          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          HTML output
         */
-       function pi_list_browseresults($showResultCount=1,$addString='',$addPart=''   {
+       function pi_list_browseresults($showResultCount=1,$addString='',$addPart='',$freeIndexUid=-1)   {
 
                        // Initializing variables:
                $pointer=$this->piVars['pointer'];
                $count=$this->internal['res_count'];
                $results_at_a_time = t3lib_div::intInRange($this->internal['results_at_a_time'],1,1000);
                $maxPages = t3lib_div::intInRange($this->internal['maxPages'],1,100);
-               $max = t3lib_div::intInRange(ceil($count/$results_at_a_time),1,$maxPages);
-               $pointer=intval($pointer);
-               $links=array();
+               $pageCount = ceil($count/$results_at_a_time);
+               $sTables = '';
 
-                       // Make browse-table/links:
-               if ($pointer>0) {
-                       $links[]='<td><p>'.$this->makePointerSelector_link($this->pi_getLL('pi_list_browseresults_prev','< Previous',1),$pointer-1).'</p></td>';
-               }
-               for($a=0;$a<$max;$a++)  {
-                       $links[]='<td'.($pointer==$a?$this->pi_classParam('browsebox-SCell'):'').'><p>'.$this->makePointerSelector_link(trim($this->pi_getLL('pi_list_browseresults_page','Page',1).' '.($a+1)),$a).'</p></td>';
-               }
-               if ($pointer<ceil($count/$results_at_a_time)-1) {
-                       $links[]='<td><p>'.$this->makePointerSelector_link($this->pi_getLL('pi_list_browseresults_next','Next >',1),$pointer+1).'</p></td>';
+               if ($pageCount > 1)     {       // only show the result browser if more than one page is needed
+                       $pointer=intval($pointer);
+                       $links=array();
+
+                               // Make browse-table/links:
+                       if ($pointer>0) {       // all pages after the 1st one
+                               $links[]='<li>'.$this->makePointerSelector_link($this->pi_getLL('pi_list_browseresults_prev','< Previous',1),$pointer-1,$freeIndexUid).'</li>';
+                       }
+
+                       for($a=0;$a<$pageCount;$a++)    {
+                               $min = max(0, $pointer+1-ceil($maxPages/2));
+                               $max = $min+$maxPages;
+                               if($max>$pageCount)     {
+                                       $min = $min - ($max-$pageCount);
+                               }
+
+                               if($a >= $min && $a < $max)     {
+                                       if($a==$pointer)        {
+                                               $links[]='<li'.$this->pi_classParam('browselist-currentPage').'><strong>'.$this->makePointerSelector_link(trim($this->pi_getLL('pi_list_browseresults_page','Page',1).' '.($a+1)),$a,$freeIndexUid).'</strong></li>';
+                                       } else {
+                                               $links[]='<li>'.$this->makePointerSelector_link(trim($this->pi_getLL('pi_list_browseresults_page','Page',1).' '.($a+1)),$a,$freeIndexUid).'</li>';
+                                       }
+                               }
+                       }
+                       if ($pointer+1 < $pageCount)    {
+                               $links[]='<li>'.$this->makePointerSelector_link($this->pi_getLL('pi_list_browseresults_next','Next >',1),$pointer+1,$freeIndexUid).'</li>';
+                       }
                }
 
                $pR1 = $pointer*$results_at_a_time+1;
                $pR2 = $pointer*$results_at_a_time+$results_at_a_time;
+               if(is_array($links))    {
+                       $addPart .= '
+               <ul class="browsebox">
+                       '.implode('',$links).'
+               </ul>';
+               }
+
+               $label = $this->pi_getLL('pi_list_browseresults_display','Displaying results ###TAG_BEGIN###%s to %s###TAG_END### out of ###TAG_BEGIN###%s###TAG_END###');
+               $label = str_replace('###TAG_BEGIN###','<strong>',$label);
+               $label = str_replace('###TAG_END###','</strong>',$label);
+
                $sTables = '<div'.$this->pi_classParam('browsebox').'>'.
                        ($showResultCount ? '<p>'.sprintf(
-                               str_replace('###SPAN_BEGIN###','<span'.$this->pi_classParam('browsebox-strong').'>',$this->pi_getLL('pi_list_browseresults_displays','Displaying results ###SPAN_BEGIN###%s to %s</span> out of ###SPAN_BEGIN###%s</span>')),
+                               $label,
                                $pR1,
                                min(array($this->internal['res_count'],$pR2)),
                                $this->internal['res_count']
                                ).$addString.'</p>':''
-                       ).$addPart.
-               '<table>
-                       <tr>'.implode('',$links).'</tr>
-               </table></div>';
+                       ).$addPart.'</div>';
 
                return $sTables;
        }
@@ -1458,12 +1742,22 @@ class tx_indexedsearch extends tslib_pibase {
                                $title = $this->linkPage($row['page_id'],htmlspecialchars($this->makeTitle($row)),$copy_row);
                        }
                } else {        // Else the page:
-                       $title = $this->linkPage($row['data_page_id'],htmlspecialchars($this->makeTitle($row)),$row);
+
+                               // Prepare search words for markup in content:
+                       if ($this->conf['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'],htmlspecialchars($this->makeTitle($row)),$row,$markUpSwParams);
                }
 
                $tmplContent = array();
                $tmplContent['title'] = $title;
-               $tmplContent['result_number'] = $row['result_number'];
+               $tmplContent['result_number'] = $this->conf['show.']['resultNumber'] ? $row['result_number'].': ' : '&nbsp;';
                $tmplContent['icon'] = $this->makeItemTypeIcon($row['item_type'],'',$specRowConf);
                $tmplContent['rating'] = $this->makeRating($row);
                $tmplContent['description'] = $this->makeDescription($row,$this->piVars['extResume'] && !$headerOnly?0:1);
@@ -1493,7 +1787,7 @@ class tx_indexedsearch extends tslib_pibase {
                $c=0;
 
                        // Traverse search words:
-               foreach($sWArr as $k => $v)     {
+               foreach ($sWArr as $k => $v)    {
                        if ($c) {
                                switch($v['oper'])      {
                                        case 'OR':
@@ -1537,7 +1831,7 @@ class tx_indexedsearch extends tslib_pibase {
                        $opt = array();
                        $isSelFlag = 0;
 
-                       foreach($optValues as $k => $v) {
+                       foreach ($optValues as $k => $v)        {
                                $sel = (!strcmp($k,$value) ? ' selected="selected"' : '');
                                if ($sel)       $isSelFlag++;
                                $opt[] = '<option value="'.htmlspecialchars($k).'"'.$sel.'>'.htmlspecialchars($v).'</option>';
@@ -1553,10 +1847,13 @@ class tx_indexedsearch extends tslib_pibase {
         *
         * @param       string          String to wrap in <a> tag
         * @param       integer         Pointer value
+        * @param       string          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 makePointerSelector_link($str,$p)      {
-               $onclick = 'document.'.$this->prefixId.'[\''.$this->prefixId.'[pointer]\'].value=\''.$p.'\';document.'.$this->prefixId.'.submit();return false;';
+       function makePointerSelector_link($str,$p,$freeIndexUid)        {
+               $onclick = 'document.'.$this->prefixId.'[\''.$this->prefixId.'[pointer]\'].value=\''.$p.'\';'.
+                                       'document.'.$this->prefixId.'[\''.$this->prefixId.'[_freeIndexUid]\'].value=\''.rawurlencode($freeIndexUid).'\';'.
+                                       'document.'.$this->prefixId.'.submit();return false;';
                return '<a href="#" onclick="'.htmlspecialchars($onclick).'">'.$str.'</a>';
        }
 
@@ -1660,46 +1957,47 @@ class tx_indexedsearch extends tslib_pibase {
                                $markedSW = '';
                                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'index_fulltext', 'phash='.intval($row['phash']));
                                if ($ftdrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))      {
-                                       $markedSW = $this->markupSWpartsOfString($ftdrow['fulltextdata']);
+                                               // 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))    {
-                               return $this->utf8_to_currentCharset($markedSW);
-                       } else {
+                       if (!trim($markedSW))   {
                                $outputStr = $GLOBALS['TSFE']->csConvObj->crop('utf-8',$row['item_description'],$lgd);
                                $outputStr = htmlspecialchars($outputStr);
-
-                               return $this->utf8_to_currentCharset($outputStr);
                        }
+                       $output = $this->utf8_to_currentCharset($outputStr ? $outputStr : $markedSW);
                } else {
-                       return '<span class="noResume">'.$this->pi_getLL('res_noResume','',1).'</span>';
+                       $output = '<span class="noResume">'.$this->pi_getLL('res_noResume','',1).'</span>';
                }
+
+               return $output;
        }
 
        /**
         * Marks up the search words from $this->sWarr in the $str with a color.
         *
-        * @param       string          text in which to find and mark up search words. This text is assumed to be UTF-8 like the search words internally is.
+        * @param       string          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.
         */
        function markupSWpartsOfString($str)    {
 
                        // Init:
                $str = str_replace('&nbsp;',' ',t3lib_parsehtml::bidir_htmlspecialchars($str,-1));
-               $str = ereg_replace('[[:space:]]+',' ',$str);
+               $str = preg_replace('/\s\s+/',' ',$str);
                $swForReg = array();
 
                        // Prepare search words for regex:
-               foreach($this->sWArr as $d)     {
-                       $swForReg[] = quotemeta($d['sword']);
+               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);
+// debug($parts,$regExString);
                        // Constants:
                $summaryMax = 300;
                $postPreLgd = 60;
@@ -1716,7 +2014,7 @@ class tx_indexedsearch extends tslib_pibase {
                $output = array();
 
                        // Shorten in-between strings:
-               foreach($parts as $k => $strP)  {
+               foreach ($parts as $k => $strP) {
                        if (($k%2)==0)  {
 
                                        // Find length of the summary part:
@@ -1726,17 +2024,17 @@ class tx_indexedsearch extends tslib_pibase {
                                        // Possibly shorten string:
                                if (!$k)        {       // First entry at all (only cropped on the frontside)
                                        if ($strLen > $postPreLgd)      {
-                                               $output[$k] = $divider.ereg_replace('^[^[:space:]]+[[:space:]]','',$GLOBALS['TSFE']->csConvObj->crop('utf-8',$parts[$k],-($postPreLgd-$postPreLgd_offset)));
+                                               $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] = ereg_replace('[[:space:]][^[:space:]]+$','',$GLOBALS['TSFE']->csConvObj->crop('utf-8',$parts[$k],$postPreLgd-$postPreLgd_offset)).$divider;
+                                               $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] = ereg_replace('[[:space:]][^[:space:]]+$','',$GLOBALS['TSFE']->csConvObj->crop('utf-8',$parts[$k],$postPreLgd-$postPreLgd_offset)).
+                                               $output[$k] = preg_replace('/[[:space:]][^[:space:]]+$/','',$GLOBALS['TSFE']->csConvObj->crop('utf-8',$parts[$k],$postPreLgd-$postPreLgd_offset)).
                                                                                $divider.
-                                                                               ereg_replace('^[^[:space:]]+[[:space:]]','',$GLOBALS['TSFE']->csConvObj->crop('utf-8',$parts[$k],-($postPreLgd-$postPreLgd_offset)));
+                                                                               preg_replace('/^[^[:space:]]+[[:space:]]/','',$GLOBALS['TSFE']->csConvObj->crop('utf-8',$parts[$k],-($postPreLgd-$postPreLgd_offset)));
                                        }
                                }
                                $summaryLgd+= $GLOBALS['TSFE']->csConvObj->strlen('utf-8', $output[$k]);;
@@ -1750,7 +2048,7 @@ class tx_indexedsearch extends tslib_pibase {
                                }
                        } else {
                                $summaryLgd+= $GLOBALS['TSFE']->csConvObj->strlen('utf-8',$strP);
-                               $output[$k] = '<span class="tx-indexedsearch-redMarkup">'.htmlspecialchars($parts[$k]).'</span>';
+                               $output[$k] = '<strong class="tx-indexedsearch-redMarkup">'.htmlspecialchars($parts[$k]).'</strong>';
                        }
                }
 
@@ -1778,7 +2076,7 @@ class tx_indexedsearch extends tslib_pibase {
 
                $outputString = $GLOBALS['TSFE']->csConvObj->crop('utf-8',$row['item_title'],50,'...');
 
-               return $this->utf8_to_currentCharset(htmlspecialchars($outputString)).$add;
+               return $this->utf8_to_currentCharset($outputString).$add;
        }
 
        /**
@@ -1789,9 +2087,12 @@ class tx_indexedsearch extends tslib_pibase {
         * @return      array           Modified template array
         */
        function makeInfo($row,$tmplArray)      {
-               $tmplArray['size'] = $this->pi_getLL('res_size','',1).' '.t3lib_div::formatSize($row['item_size']).'';
-               $tmplArray['created'] = $this->pi_getLL('res_created','',1).' '.date('d-m-y',$row['item_crdate']).'';
-               $tmplArray['modified'] = $this->pi_getLL('res_modified','',1).' '.date('d-m-y H:i',$row['item_mtime']).'';
+               $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'];
+               $timeFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
+
+               $tmplArray['size'] = t3lib_div::formatSize($row['item_size']);
+               $tmplArray['created'] = date($dateFormat, $row['item_crdate']);
+               $tmplArray['modified'] = date($dateFormat.' '.$timeFormat, $row['item_mtime']);
 
                $pathId = $row['data_page_id']?$row['data_page_id']:$row['page_id'];
                $pathMP = $row['data_page_id']?$row['data_page_mp']:'';
@@ -1801,7 +2102,11 @@ class tx_indexedsearch extends tslib_pibase {
                        $tmplArray['path'] = '<a href="'.htmlspecialchars($row['data_filename']).'">'.htmlspecialchars($row['data_filename']).'</a>';
                } else {
                        $pathStr = htmlspecialchars($this->getPathFromPageId($pathId,$pathMP));
-                       $tmplArray['path'] = $this->linkPage($pathId,htmlspecialchars($pathStr),array('data_page_mp'=>$pathMP));
+                       $tmplArray['path'] = $this->linkPage($pathId,$pathStr,array(
+                               'data_page_type' => $row['data_page_type'],
+                               'data_page_mp' => $pathMP,
+                               'sys_language_uid' => $row['sys_language_uid'],
+                       ));
                }
 
                return $tmplArray;
@@ -1820,7 +2125,7 @@ class tx_indexedsearch extends tslib_pibase {
                $rl = $this->getRootLine($pathId,$pathMP);
                $specConf = $this->conf['specConfs.']['0.'];
                if (is_array($rl))      {
-                       foreach($rl as $dat)    {
+                       foreach ($rl as $dat)   {
                                if (is_array($this->conf['specConfs.'][$dat['uid'].'.']))       {
                                        $specConf = $this->conf['specConfs.'][$dat['uid'].'.'];
                                        break;
@@ -1854,9 +2159,15 @@ class tx_indexedsearch extends tslib_pibase {
                                        // Flag code:
                                $flag = $rowDat[0]['flag'];
                                if ($flag)      {
-                                       $file = 't3lib/gfx/flags/'.$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($rowDat[0]['title']).'" alt="'.htmlspecialchars($rowDat[0]['title']).'" />';
                                                return $output;
@@ -1886,16 +2197,21 @@ class tx_indexedsearch extends tslib_pibase {
         * @param       integer         Page id
         * @param       string          Title String to link
         * @param       array           Result row
+        * @param       array           Additional parameters for marking up seach words
         * @return      string          <A> tag wrapped title string.
         */
-       function linkPage($id,$str,$row=array())        {
+       function linkPage($id,$str,$row=array(),$markUpSwParams=array())        {
 
                        // Parameters for link:
-               $urlParameters = unserialize($row['cHashParams']);
+               $urlParameters = (array)unserialize($row['cHashParams']);
 
                        // Add &type and &MP variable:
                if ($row['data_page_type']) $urlParameters['type'] = $row['data_page_type'];
                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->domain_records[$id]))      {
@@ -1911,14 +2227,14 @@ class tx_indexedsearch extends tslib_pibase {
                        $addParams = '';
                        if (is_array($urlParameters))   {
                                if (count($urlParameters))      {
-                                       reset($urlParameters);
-                                       while(list($k,$v)=each($urlParameters)) {
-                                               $addParams.= '&'.$k.'='.rawurlencode($v);
-                                       }
+                                       $addParams.= t3lib_div::implodeArrayForUrl('',$urlParameters);
                                }
                        }
 
-                       return '<a href="'.$scheme.$firstDom.'/index.php?id='.$id.$addParams.'" target="'.$this->conf['search.']['detect_sys_domain_records.']['target'].'">'.htmlspecialchars($str).'</a>';
+                       if ($target=$this->conf['search.']['detect_sys_domain_records.']['target'])     {
+                               $target = ' target="'.$target.'"';
+                       }
+                       return '<a href="'.htmlspecialchars($scheme.$firstDom.'/index.php?id='.$id.$addParams).'"'.$target.'>'.htmlspecialchars($str).'</a>';
                } else {
                        return $this->pi_linkToPage($str,$id,$this->conf['result_link_target'],$urlParameters);
                }
@@ -1949,7 +2265,7 @@ class tx_indexedsearch extends tslib_pibase {
        function getFirstSysDomainRecordForPage($id)    {
                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('domainName', 'sys_domain', 'pid='.intval($id).$this->cObj->enableFields('sys_domain'), '', 'sorting');
                $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
-               return ereg_replace('\/$','',$row['domainName']);
+               return rtrim($row['domainName'], '/');
        }
 
        /**
@@ -2018,6 +2334,7 @@ class tx_indexedsearch extends tslib_pibase {
                        while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))       {
                                $output[$row['uid']] = $GLOBALS['TSFE']->sys_page->getPageOverlay($row);
                        }
+                       $GLOBALS['TYPO3_DB']->sql_free_result($res);
                        return $output;
                } else {
                        return $GLOBALS['TSFE']->sys_page->getMenu($id);
@@ -2068,4 +2385,5 @@ class tx_indexedsearch extends tslib_pibase {
 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/indexed_search/pi/class.tx_indexedsearch.php'])       {
        include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/indexed_search/pi/class.tx_indexedsearch.php']);
 }
+
 ?>