Changes to indexed_search
authorKasper Skårhøj <kasper@typo3.org>
Mon, 14 Feb 2005 17:23:56 +0000 (17:23 +0000)
committerKasper Skårhøj <kasper@typo3.org>
Mon, 14 Feb 2005 17:23:56 +0000 (17:23 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@560 709f56b5-9817-0410-a4d7-c38de5d9e867

16 files changed:
ChangeLog
typo3/sysext/cms/tslib/class.tslib_content.php
typo3/sysext/cms/tslib/class.tslib_menu.php
typo3/sysext/cms/tslib/class.tslib_pibase.php
typo3/sysext/cms/tslib/class.tslib_search.php
typo3/sysext/indexed_search/class.external_parser.php
typo3/sysext/indexed_search/class.indexer.php
typo3/sysext/indexed_search/doc/TODO.txt
typo3/sysext/indexed_search/doc/manual.sxw
typo3/sysext/indexed_search/ext_localconf.php
typo3/sysext/indexed_search/ext_tables.sql
typo3/sysext/indexed_search/ext_typoscript_setup.txt
typo3/sysext/indexed_search/mod/index.php
typo3/sysext/indexed_search/modfunc1/class.tx_indexedsearch_modfunc1.php
typo3/sysext/indexed_search/pi/class.tx_indexedsearch.php
typo3/sysext/indexed_search/pi/locallang.php

index e08c67f..7eea6c6 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2005-02-14  Kasper Skårhøj,,,  <kasper@typo3.com>
+
+       * Large number of updates to system extension indexed_search, in particular to the frontend search plugin which is now ready for implementation of templating engine by workgroup. still missing work on the lexer to support CJK content.
+
 2005-02-11  Andreas Otto  <andreas.otto@dkd.de>
 
        * In order to use enableTypeByConfig on more types than Input and Text the variable $specConf had to be set. This was done to all getSingleField_* methods which use $this->renderWizards. A list of the methods is provided in the commit message.
 
        * Added a check to class t3lib_htmlmail to check if postfix version 1.XX is used. If this is the case the -f parameter is not used for call to mail(). This should fix the problem with mails not being sent when using Postfix as MTA..
 
-2005-01-21  Kasper Sk�hj,,,  <kasper@typo3.com>
+2005-01-21  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added a new feature to force all UIDs in the "impexp" extension.
 
-2005-01-14  Kasper Sk�hj,,,  <kasper@typo3.com>
+2005-01-14  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * import/export: CSH for the whole module, localization of all labels
 
-2005-01-02  Kasper Sk�hj,,,  <kasper@typo3.com>
+2005-01-02  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added Karsten D.s patches for DBAL.
 
-2004-12-20  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-12-20  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Changed "config.disableContentLengthHeader" over to "enableContentLengthHeader" because a default content-length header might introduce some weird and hard-to-debug situation for people.
        * Added possibility to enable cache-control headers on frontend output; This allows a site to be cached by client browsers and proxies. See TSref for configuration ("config.sendCacheHeaders")
@@ -62,7 +66,7 @@
        * Fixed bug that gave inconsistent SYS_LASTCHANGED values whether a page was gotten from cache or generated.
        * Added check for explicitAllow/Deny in the content element wizard (during a trainride from Allerd in S-Tog line A to Nrreport - thats all it took).
 
-2004-12-17  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-12-17  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Mainly: Did tons of improvements on the import/export module (system extension "impexp").
                Main features:
@@ -89,7 +93,7 @@
        * Added support for having temporary files in typo3temp/ prefixed with a meaningful prefix, typically coming from the menu title, original image name etc.
 
 
-2004-11-28  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-11-28  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Main feature: Lots of updates on Indexed Search extension. The changes are mainly in the indexer, not the search plugin. The work is NOT FINISHED yet and don't update a production site with this work! One main thing to be aware of is that all indexing is done internally as utf-8. You should flush your old index tables before running the new one.
        * Fixed bug in t3lib_cs::utf8_strtrunc() (or so)... do'h Martin!
        * TYPO3_CONF_VARS[BE][adminOnly] is now an integer value (was boolean by mistake)
        * Added missing description of 3rd parameter for the crop function in class.tslib_content.php
 
-2004-11-18  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-11-18  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * !!! Moved ALL core localizations into language packs found in extensions prefixed "csh_[language key]". The consequence of this is that the backend will work in english until the proper language pack is installed for the language the user has selected. This step is taken to make backend localization more scalable and prevent the huge memory problems we have with ll-XML and 3.7.0. The "csh_*" extensions are NOT available in TER at the moment, but the whole bunch can be downloaded from http://130.228.0.33/t3dl/src/all_39_language_packs_as_local_extensions.tgz
 
 
        * Implemented #0000508: Minor performance improvement in an if clause in t3lib_stdgraphic, thanks to Volker Graubaum.
 
-2004-11-17  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-11-17  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Converted locallang*.php to locallang*.xml in new system extensions.
 
 
        * Fixed bug #0000416: Removing spurious DEFAULT '0' in SQL create table statements of uid columns right before they're executed in t3lib_install.
 
-2004-11-16  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-11-16  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Moved the remaining global extensions to sysext/ which were selected to be system extension.
        * Added configuration option in TYPO3_CONF_VARS[FE][lifetime] so the frontend users cookies can be set to a lifetime in seconds. Currently the cookie lasts only for the browser session and not more.
 
-2004-11-15  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-11-15  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Merged all changes from "TYPO3_3-7" branch
        * Changed to version 3.8.0-dev
  * Release of TYPO3 3.7.0
  * Increased version number to 3.7.0
 
-2004-09-24  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-09-24  Kasper Skårhøj,,,  <kasper@typo3.com>
 
  * Updated backend localizations for 3.7.0 Release
  * Tagging the release with "TYPO3_3-7-0"
 
  * Fixed bug #0000111: Install tool now allows for database name, password and username to contain any kind of chars (not limited to alphanumerical any more).
 
-2004-09-14  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-09-14  Kasper Skårhøj,,,  <kasper@typo3.com>
 
  * Updated my email address from "kasper@typo3.com" (which is closed and will stay that way) to "kasperYYYY@typo3.com" which programmers should be able to figure out...
        * Updated all JavaDoc comments and function/class indexes in files, preparing for 3.7.0RC
 
-2004-09-13  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-09-13  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added CSH for Web>Info/Localization Overview
 
-2004-09-13  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-09-13  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Changed little more in uniqueList, among others that a fixed number of paramters are supported only now!
 
 
        * Fixed bug in t3lib_div::uniqueList that was caused when t3lib_div::uniqueArray was replaced with array_unique. Obviously array_unique doesn't remove empty values from the array but t3lib_div::uniqueArray did! Please take care of this if you still use this deprecated function in your extension!
 
-2004-09-11  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-09-11  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Updated changelog for 09/09
        * Fixed bug in stdgraphic::fontResize that made it go into eternal loops if the size could not be obtained in the lower end, basically when fontsize reached zero...
        * Fixed problem with empty URLs in menu generation. Empty URLs may occur when a realurl points to the frontpage (which is a blank suffix to the base url). In such cases the URL now becomes the baseUrl of the site (if that is configured!). This should fix it very specifically for all realurl cases.
        * Fixed install tools incapability to delete files with certain prefixes in typo3temp/ folder.
 
-2004-09-09  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-09-09  Kasper Skårhøj,,,  <kasper@typo3.com>
 Sorry for writing these changelog entries with a delay of two days. I write them based on a CVS patch and it took ages to make that from a parking lot in Suresnes, Paris, 4 am in the morning. Its becoming harder to find a stable hotspot in Paris I think... But here we go:
        * Changed all HTTP_*_VARS to $_* superglobals. Also raised PHP requirement version to 4.1.0
        * Added wrapping functions to array browser class. Also updated the Configuration module to use these features so you can now click a key and get a string served ready to implement in eg. localconf.php
@@ -260,34 +264,34 @@ Sorry for writing these changelog entries with a delay of two days. I write them
 2004-09-00  Jan-Erik Revsbech    <jer@moccompany.com>
        * Fixed bug #292 concerning Return path in class.t3lib_mailer.php. The fix has a seperate solution for windows and Unix. The unix fix does however not work with safe_mode enabled. Do not know how to overcome this. Perhaps an environment variable for sendmail can be specified? The fix for windows works OK with safe_mode on since, it does not rely on passing parameter directly to the mailer tranport agent (Sendmail or postfix), but instead sets the php variable sendmail_from, which has no effect on Unix systemt.
 
-2004-09-02  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-09-02  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed a few basic PHP5 problems (aiming at PHP5 support in 3.7.0)
 
-2004-09-02  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-09-02  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * BTW; Just created a hook for page indexing which "indexed_search" will also be using in near future - BUT at the time of this writing it will require a new version of indexed_search for you and that is NOT ready yet - so indexed_search will NOT work for you anymore before you get the new version of this extension!
 
-2004-09-02  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-09-02  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added Catalan, Bosnian and Korean languages.
 
-2004-08-29  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-08-29  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added a wildcard like option for values in the "language" condition in frontend (matchcondition class). Can now match any language found in the HTTP_ACCEPT_LANGUAGE value.
 
-2004-08-29  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-08-29  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added "lockIP" setting for backend users - this will solve the problem that some has reported about backend users not being able to login with 3.7.0...
        * Added new HMENU special type, "language", which can generate a language selector using the "&L" variable directly.
        * Added option for HMENU (protectLvar) so menu items linking to pages that are not translated will have their "&L" var set to zero, thus reverting to the default language.
        * Corrected a bug in menu generation: Spacers for TMENU had a link around it - this was a bug, correct now. No links on spacer elements!
 
-2004-08-26  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-08-26  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Adding editlock icon in Web>Access
 
-2004-08-26  Kasper Sk�hj,,,  <kasperYYYY@typo3.com>
+2004-08-26  Kasper Skårhøj,,,  <kasperYYYY@typo3.com>
 
        * Bugfix: in browse_links where the record listing contained links to clickmenus:
        * Added "Save and View" support for records which has another language set; For instance content elements and page overlay records will now view the page with the "&L=xx" parameter set to the language they represent.
@@ -302,7 +306,7 @@ Sorry for writing these changelog entries with a delay of two days. I write them
        * Changed calling order of TSFE->getCompressedTCarray() in "index_ts.php": Now it loads before ->getConfigArray(). Should be no difference to anyone except internal processing in tslib_fe which can now access the array a little before it usually could.
        * Added t3lib_cs::convArray() for charset conversion of array contents.
 
-2004-08-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-08-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Implemented versioning API in tcemain plus other places. Still not functional for the broad public (will be in 3.8.0). Missing conceptual testing, implementation in the backend interface (still to be discussed how that is best done and fitting workflow) and not at all in the frontend.
        * Tables configured for versioning by default is pages, tt_content, pages_language_overlay and sys_template
@@ -318,7 +322,7 @@ Sorry for writing these changelog entries with a delay of two days. I write them
                The new version of the Kickstarter that uses these new ways of interaction has the new extension key 'kickstarter' and is already available from typo3xdev CVS.
                The old version of the Kickstarter having the key 'extrep_wizard' is not used anymore.
 
-2004-08-21  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-08-21  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added support for backend initialization in PHP shell scripts. Interesting for deamons, cronjobs etc where you want a PHP script to run from shell but with a full backend environment. Documented in next version of Inside TYPO3.
        * Configurable multiplication of DB field size (useful for resizing database for UTf-8 support)
@@ -352,7 +356,7 @@ Sorry for writing these changelog entries with a delay of two days. I write them
 
  * Corrected wrong parameter order for some implode function calls.
 
-2004-08-07  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-08-07  Kasper Skårhøj,,,  <kasper@typo3.com>
 
  * Added three new permission modes for backend users: 1) Localization access control, 2) Access control on value level (for instance allow/deny individual selectorbox values), 3) API for custom permission options.
  * Implemented control of these modes in tcemain, tceforms and alt_doc.php + QuickEdit. Still need to implement it for edit icons around, but this is not critical, mostly a usability issue.
@@ -361,22 +365,22 @@ Sorry for writing these changelog entries with a delay of two days. I write them
  * Finished the accessListRenderMode(s) (see 4/8 below)
  * Still unsettled about various default settings related to these new options, but will discuss on dev-list.
 
-2004-08-04  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-08-04  Kasper Skårhøj,,,  <kasper@typo3.com>
 
  * Added new rendering modes for the "select" type in TCA: You can now render multiple-select lists as either a SINGLE selector box with multiple value selection OR as a list of checkboxes. For mozilla even the icons are rendered nicely in the option tags. Check out the backend user group configurations. Work is still in progress.
 
-2004-08-04  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-08-04  Kasper Skårhøj,,,  <kasper@typo3.com>
 
  * Added TYPo3_CONF_VARS[FE][lockHashKeyWords] so it is optional to lock FE user sessions to HTTP_USER_AGENT
 
-2004-08-03  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-08-03  Kasper Skårhøj,,,  <kasper@typo3.com>
 
  * Added and Changed features around page languages. More to come including a document guiding people about charsets and localization.
 
 2004-07-24  Jan-Erik Revsbech <jer@moccompany.com>
  * Added support for other transfer encodings in the dmailer class. Will start to move the t3lib_directmailer class out of the core and into the direct_mail extension.
 
-2004-07-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-07-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
  * Added the Core CVS rules to repository at "misc/core_cvs_rules.txt". ALL Contributers to the CORE CVS SHOULD READ AND FOLLOW THIS!
 
@@ -397,7 +401,7 @@ Sorry for writing these changelog entries with a delay of two days. I write them
 
  * Fixed bug #0000191: Small typo in German translation
 
-2004-06-28  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-06-28  Kasper Skårhøj,,,  <kasper@typo3.com>
 
  * Moved creation of menu graphics, scaled images, gifbuilder images and temporary image files into subfolders of typo3temp/
  * Fixed case-folding-cache-file bug in t3lib_cs...
@@ -407,7 +411,7 @@ Sorry for writing these changelog entries with a delay of two days. I write them
 
  * Fixed bug #0000119: Another fe_adminLib htmlspecialchars() issue
 
-2004-06-19  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-06-19  Kasper Skårhøj,,,  <kasper@typo3.com>
 
  * Moved CSH locallang-XML labels into extensions prefixed "csh_".
 
@@ -432,51 +436,51 @@ Sorry for writing these changelog entries with a delay of two days. I write them
        * Fixed bug #0000070: Number of files (file count) displayed in file list module was one number too high ("5 Files" although 4 only exist). Updated typo3/class.file_list.inc
        * Changed one line in media/scripts/plaintextLib.inc which caused a "page not found" in some e-mail clients.
 
-2004-06-06  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-06-06  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Changed all locallang files from "lang" system extension into the new locallang-XML format instead. Includes changes to a bunch of core scripts which had to include the new files with an API function from the $LANG object.
 
-2004-06-06  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-06-06  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added "groupChangeMask" option in TYPO3_CONF_VARS - makes it possible to set which group newly created files and folders will get. (Thanks to Stucki)
 
-2004-06-03  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-06-03  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added API for configuring tables (ending on "cache") that are flushed together with "Clear All Cache".
        * Fixed that the Admin Panel is always on top (z-index : 0;
 
-2004-06-03  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-06-03  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added base url to typo3 error dialog in frontend. Means it shows logo when using realurls now.
        * Added "READFILE:" prefix for pageNotFound handler in frontend; This will read the contents of an html file and output with substitution of a few marker strings.
        * Added feature in page tree; Temporary mounting a point in the users page tree as root. (available in the "More options..." - needs upgrade of that extension as well...).
        * Fixed frontend edit icons under real-url conditions. They didn't work in MSIE. Had to prefix them with base url.
 
-2004-05-29  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-29  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed bug; All page types (doktype) was shown to uses even if they were not all in their list of possible type values.
 
-2004-05-29  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-29  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Created a new DEFAULT backend module called "manual". It shows a TOC of CSH items from the system. This will provide a "user sensitive" manual inside of TYPO3 with localized content to the extend that translators has translated CSH labels in the system. The vision is that the Documentation Team will develop CSH content so far that this will become a really good inline reference for users of TYPO3. Also, extension authors are encouraged to implement CSH for their tables and backend modules and let that be the user manual for their products!
 
-2004-05-28  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-28  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added new CSH entries at various places using a new method in t3lib_BEfunc. The CSH entries are still empty and needs to be completed.
 
-2004-05-28  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-28  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added visual response to backend module selection in the menus; The class attribute of the menu items is changed when a module is selected. The default stylesheet is modified so this results in the current module being highlighted in the menu.
 
-2004-05-27  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-27  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed various things in file processing, t3lib_extFileFunc et al.
 
-2004-05-24  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-24  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added API for custom RTE transformations. Documented in upcoming "TYPO3 Core API".
 
-2004-05-20  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-20  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed remaining issues with styles in the backend regarding the TCEforms. There has been added additional possibilities of styling forms, now with classes in stylesheets, using $TBE_STYLES to set them up. Documentation of $TBE_STYLES for TCeforms has been updated in TYPo3 Core Api as well.
 
@@ -486,196 +490,196 @@ Sorry for writing these changelog entries with a delay of two days. I write them
                #83: On non open_basedir'ed systems check if IM executables exist before trying to execut them.
                #95: Use ini_get() instead of get_cfg_var()
 
-2004-05-19  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-19  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed stylesheet issues in Extension Manager.
 
-2004-05-19  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-19  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Finally fixed typo3/show_item.php and typo3/wizard_colorpicker.php scripts for TYPO3 3.6.0 compliance. Now only extensions and some t3lib/ are missing clean-up.
 
-2004-05-18  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-18  Kasper Skårhøj,,,  <kasper@typo3.com>
        * Added t3lib_cs::specCharsToASCII() for converting special chars (like umlauts) to their double-byte alternatives in ASCII (like au, oe etc...). Function is NOT finished at all, only added so I could use it for the conversion of filenames in simulateStaticDocuments.
        * TypoScript charset compatibility extended: tslib_cObj::caseshift(), tslib_cObj::substring(), tslib_cObj::crop() uses functions in t3lib_cs now. Also stdWrap.strftime will automatically convert localized string from locale charset (guessed by t3lib_cs) to renderCharset.
        * !!! website charset is now taken from "forceCharset" by default (if found) and in any case the http-header with text/html and charset is sent UNLESS you disable it with "config.disableCharsetHeader=1". You will probably have to disable this header if you are using TYPO3 for XML feeds or wap-pages.
        * Added "config.renderCharset" option: This is the charset of the content while rendered in the frontend engine. If different from "metaCharset" a conversion must happen before output to browser. Both renderCharset and metaCharset takes their default values from TYPO3_CONF_VARS[BE][forceCharset] if found, otherwise they default to "iso-8859-1". Also "metaCharset" takes "renderCharset" as default - and if metaCharset is different from renderCharset a conversion will happen on output.
 
-2004-05-18  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-18  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Created new function, t3lib_div::fixed_lgd_cs(), which should be used in the backend wherever a string is shortend for visual display. This function will truncate the string according to the backend charset (which should of course be set by forceCharset to a fixed value). This new function has also been substituted numerous places in the source of course (hence all the script updates).
 
-2004-05-17  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-17  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Moved "install" extension to be a sys extension in sysext/
 
-2004-05-17  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-17  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Corrected some bugs in t3lib_cs while writing a unit test for it.
 
-2004-05-15  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-15  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Splitted the Install Tool interface parts out from t3lib_install into the class tx_install (in extension "install"). Only things left are logic to update localconf.php files and manage SQL / Database (for Extension Manager).
 
-2004-05-11  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-11  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Changed version number to 3.7.0-dev according to newly adopted major.minor.patch version numbering model.
 
-2004-05-11  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-11  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Merged branch changes from "TYPO3_3-6-0"; Mainly bugfixes by ingmar.
 
-2004-05-11  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-11  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Rolled back browser detection in matchcondition class.
 
-2004-05-07  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-05-07  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added "relPathprefix" to TEMPLATE cObject and also added support for relative path substitution of references in url() wrappers in <style> tags. This will also fix THAT problem reported for automaketemplate.
 
-2004-04-30  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-30  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Merged TYPO3_3-6-0 branch changes by robert into HEAD. See 3.6.0 branch change log if you want.
 
-2004-04-27  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-27  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * TAG: "TYPO3_3-6-0RC2", BRANCH "TYPO3_3-6-0"
 
-2004-04-26  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-26  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added possibility to prefix references to wizard scripts with "EXT:" for reference to wizard scripts in extension.
 
-2004-04-26  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-26  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added prefix to relative file reference in @import style sheet
 
-2004-04-26  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-26  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed bug where DB mounts for a user which has been deleted would still show up in the page tree.
 
-2004-04-26  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-26  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed bug with pageNotFound handling.
 
-2004-04-26  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-26  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added a PAGE Tsconfig option to disable the automatic clearing of page cache when records are edited.
 
-2004-04-26  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-26  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Updated "cms" extension with most recent labels from TYPO3.org
 
-2004-04-26  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-26  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Updated "lang" extension with most recent labels from TYPO3.org
 
-2004-04-26  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-26  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added Latvian, Japanese and Vietnamese languages
 
-2004-04-24  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-24  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added to TypoScript object browser that the title text of the object links contains information about in which lines in the TypoScript body code that a certain object path is set, cleared, copied.
 
-2004-04-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added "removeBadHTML" option to stdWrap - this can help to avoid XSS dangerous HTML.
 
-2004-04-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added feature in TYpoScript data type "getText" to get values from GET arrays via "GPvar" key word. Now you can specify ".date = GPvar : tx_myext|mode|index" to get value of &tx_myext[mode][index]
 
-2004-04-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added option "$TYPO3_CONF_VARS["GFX"]["gdlib_2"] = 'no_imagecopyresized_fix';" to avoid using the imagecopyresized workaround in stdgraphic class which has failed for some. Whether the workaround is needed anymore is not certain. Some people say it works fine without.
 
-2004-04-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added TypoScript condition "hostname" for matching hostnames for IP addresses.
 
-2004-04-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added API for configuring extra tables/fields for listing in Web > Page
 
-2004-04-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added option "mod.web_list.clickTitleMode = edit/info/show" to determine alternative behaviours of title links in the Web > List module.
 
-2004-04-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added Page TSconfig option "mod.web_list.listOnlyInSingleTableView = 1" which makes the List module list only the table names by default. You have to click the table name to get the single-table view before records show up. This is useful for pages containing many records from many tables.
 
-2004-04-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added refresh button to taskcenter (not in core CVS)
 
-2004-04-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added "Login failure" message in backend login box
 
-2004-04-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added to user authentication that the HTTP_USER_AGENT is hashed and a part of the session lookup (in other words, if the HTTP_USER_AGENT stays constant the session stays as well). Also added possibility of configuring that the IP adresse used to lock down sessions is only part 1,2,3 or 4 (all) used. Mainly this is easily configurable for frontend users (which has had the "security level" set to "2" now instead of disabled totally!). For backend users I didn't make configuration options in TYPO3_CONF_VARS - just wanted to know if people needed it there first (not to bloat options....)
 
-2004-04-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added possibility of jumping directly to editing a page in the backend. You specify "alt_main.php?edit=[page id]" and you will be brought directly to the page edit module.
 
-2004-04-22  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-22  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added in RTE link box: Searched *into* Content ELements of type Text and Text w/Image after anchors (<a name="...">) and lists them as well with content elements to which an anchor link can be made.
 
-2004-04-22  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-22  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added configuration options for what level of pages cache is cleared when you edit a page header. You can not get children and grand-parents cleared as well. (TCEMAIN.clear..... in Page TSconfig)
 
-2004-04-21  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-21  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added "altText" and "titleText" attributes to the IMGMAP object (used for IMGMENU: Now you can add values to the alt and title attributes of image maps).
        * Added "ATagTitle" attribute for TMENU / GMENU so the menu links can have a title attribute for accessible websites.
        * Added "allStdWrap" attributes for TMENUITEM/GMENU item states. + some other properties requested.
 
-2004-04-21  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-21  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added features around "includeCSS" TypoScript property for PAGE objects: "import" and "alternate" attributes (booleans) are now supported.
 
-2004-04-20  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-20  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Changed a bunch of things, added a few new features to make TYPO3 accessible. One significant thing was the attributes "altText", "titleText" and "longdescURL" for IMAGE, IMGTEXT, FILE and ->filelink() in TypoScript.
 
-2004-04-20  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-20  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Completed changes for XHTML compliance requests from the Accessibility group. Mainly adding support for more XHTML types, adding attributes like xml:lang to <html> tag, support for "dir" attributes in HTML tags, support for writing inline styles and JavaScript to a temporary file to keep a clean HTML <head> section...
 
-2004-04-19  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-19  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * "minItems", "maxItems" and "begin" has been added as properties to MENU objects (like TMENU, GMENU, IMGMENU etc) so you can set these values for the individual menus (as they probably should have been in the first place...).
 
-2004-04-19  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-19  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added a checkbox to the page header in the "cms" extension called "Hide in menu". With this checkbox the page is excluded from menus on the totally same terms as doktype=5 ("Not in menu") does. The implementation is believed to be complete (although there might be some places overlooked). The checkbox renders the doktype 5 "Not in menu" obsolete; the idea is that the checkbox should be used in the future. Finally - if anyone read this far - I prophecise, that within two weeks from this moment someone will approach me and want to have a visual response to the "Hide in menu" checkbox in the icon; currently the page icon does NOT change it looks (and it would be very doubtful if we could justify making it change...).
 
-2004-04-19  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-19  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added new FORM cObject type, "label", which inserts a label instead of a field. Also fixed ordering problem when the "dataArray" attribute of FORM is used (now renders the form in the numerical order of the elements instead of order of appearance).
 
-2004-04-19  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-19  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed incompatibility between Mount Points and property "overrideId" in menus.
 
-2004-04-19  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-19  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added support for JavaScript regular expression evaluation in FORM cObject. Means that fields in formmails can now be checked for a pattern and not only for "required".
 
-2004-04-19  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-19  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added possibility to copy database/file elements attached to records; You can now click the icon of these elements in the editing forms and get a (limited) context menu for these elements.
        * Fixed some other bugs around.
 
-2004-04-16  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-16  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * fixed detection of schemes (http://, ftp:// etc) in "typolinks". Now email addresses are detected only if NOT prepended with a scheme. Also the presence of a scheme will make typolink function detect the input as a plain URL which should just be passed through untouched.
 
-2004-04-14  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-14  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Mount Points (Mount pages) reworking:
 Changelog:
@@ -708,90 +712,90 @@ Fixed bugs in Mount Points / Status:
                * Affected files: t3lib/class.t3lib_stdgraphic.php, typo3/sysext/cms/ext_tables.sql
                * Tested by Ingmar, Michael and Robert
 
-2004-04-01  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-01  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed problem with domain look-up when an extra "/" was added to eg. "typo3.com//" -> showing "typo3.org" instead
 
-2004-04-01  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-01  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed some browser detection bugs in t3lib_matchcondition and t3lib_div. Not necessarily exhaustive! For instance a report on Netscape 7.2 being wrongly detected may not be resolved (need teh value of HTTP_USER_AGENT to solve it since I do not have netscape 7.2!)
 
-2004-04-01  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-01  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added full safety for the internal TYPO3 formmail; email addresses in the fields "recipient" and "recipient_copy" are encrypted in the transfer and the "formmail" interface is safe for spam-misuse (since a proper recipient address cannot be forged automatically).
 !!!If someone are using the "formmail" API from other renderers than the FORM cObject in TypoScript you will have to set the recipient address to the encrypted value by default OR alternatively disabled the check by TYPO3_CONF_VARS[FE][strictFormmail] = FALSE
 
-2004-04-01  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-01  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added Jens Ellerbrocks suggestion for "postUserFuncInt" in stdWrap.
 
-2004-04-01  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-01  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added some file icons from Ben and Emile
 
-2004-04-01  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-01  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added "General Plugin" to content elmeent wizard list.
 
-2004-04-01  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-04-01  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed SSL problem and many other minor things
 
-2004-03-31  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-03-31  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed spam-protection of email adresses inserted by "mailto:..." in text.
 
-2004-03-31  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-03-31  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed another small bug in detection of simulateStaticDocuments.
 
-2004-03-31  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-03-31  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed distinction between ' and " in EM.
 
-2004-03-31  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-03-31  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Removed "onblur" handler in "browser.php" - had no great significance apparently and bugged people on Mac.
 
-2004-03-31  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-03-31  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * In t3lib_div::linkThisUrl(), remove "?" if no parameters were found.
 
-2004-03-31  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-03-31  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added "config.doctype = none" support - omits any doctype in the frontend.
 
-2004-03-31  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-03-31  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed an error for form wizard (and others...) where the return URL would be wrong if the wizard was activated right after having saved a new record (would like back to a new record again).
        * Further, I added the option of xmlOutput from the table and form wizards. This option is configured in the wizard setup. There is NO frontend rendering supporting the XML format yet. But it might be very handy (and recommended) for other applications wanting to use the table and formwizards.
 
-2004-03-31  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-03-31  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Changed the way simulateStaticDocuments are resolved
 
-2004-03-28  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-03-28  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Changed "t3lib_div::calluserFunc" and t3lib_div::getUserObj to use "&" as token for persistent (global) objects rather than ">" - PLEASE UPDATE YOUR CODE if you happend to use these features already (less than a week old).
 
-2004-03-24  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-03-24  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added <span title=""> to path in backend modules in Web main module; you can now see the full path (non-truncated) as title text.
 
-2004-03-24  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-03-24  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added RTE API and changed the "rte" extension to use that.
        * Added t3lib_div::getUserObj() which returns an OBJECT , instead of executing a method call like callUserFunc() does.
 
-2004-03-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-03-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed problem in Extension Manager where files and directories was not written with correct permissions. I also added t3lib_div::mkdir() general function for creating directories.
 
-2004-03-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-03-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Fixed bug that page tree didn't unfold when entering page id in the shortcut frame.
 
-2004-03-23  Kasper Sk�hj,,,  <kasper@typo3.com>
+2004-03-23  Kasper Skårhøj,,,  <kasper@typo3.com>
 
        * Added a checkbox for be-users to disable IP locking. This is useful if you have backend users complaining about being thrown off sessions.
 
@@ -837,7 +841,7 @@ Made changes to class.tslib_content.php:
 - added title="" when neccessary, ie. all cleargifs havin an alt="" parameter now also have a title=""
 
 
-Kasper Sk�hj, 6/2:
+Kasper Skårhøj, 6/2:
  - Added processing option to RTE, "proc.plainImageMode"
  - Added options for select and group types in TCA to set the selector box style.
  - Added $altPageId parameter to function linkTP*() in tslib_pibase + pi_list_linkSingle()
@@ -846,7 +850,7 @@ Kasper Sk�hj, 6/2:
  - Implemented pop-up window size selector in link wizard
 
 
-Kasper Sk�hj
+Kasper Skårhøj
        * Removed "mininews" from global extensions - that was an error in RC1
        * Removed global extensions "beuser_tracking/ classic_welcome/ design_components/ tt_links/" from main distribtion. They are either obsolete or irrelevant and it has been considered responsible to remove them like this.
 
@@ -872,13 +876,13 @@ Changed all usage of t3lib_div::GPvar('SET') to t3lib_div::GPvar('SET',1) (strip
 
        * Added and changed some features related to the replacement of default page module by a custom one (templavoila). See t3lib_positionmap, t3lib_tsfebeuserauth, alt_shortcut, alt_clickmenu
 
-2003-12-16  Kasper Sk�hj
+2003-12-16  Kasper Skårhøj
 
        * Added new languages labels for cms and lang extensions // increased version number to 3.6.0RC1
 
-2003-12-16  Kasper Sk�hj
+2003-12-16  Kasper Skårhøj
        * Changed order of DOCTYPE and XML declaration for XHTML support (for standards compliance mode detection in MSIE)
-2003-10-24  Kasper Sk�hj
+2003-10-24  Kasper Skårhøj
        * Moved changelog.txt to ChangeLog ("cvs compliant")
 TYPO3 3.6.0-dev
 PHP:
index 17bd0fc..c9655ba 100755 (executable)
@@ -6007,7 +6007,7 @@ class tslib_cObj {
 #??                                            $GLOBALS['TSFE']->sys_page->versionOL('pages',$row);
                                        }
                                                // Add record:
-                                       if (is_array($row) && $dontCheckEnableFields || $GLOBALS['TSFE']->checkPagerecordForIncludeSection($row))       {
+                                       if (is_array($row) && ($dontCheckEnableFields || $GLOBALS['TSFE']->checkPagerecordForIncludeSection($row)))     {
                                                        // Add ID to list:
                                                if ($begin<=0)  {
                                                        if ($dontCheckEnableFields || $GLOBALS['TSFE']->checkEnableFields($row))        {
index 38722e6..67fae68 100755 (executable)
@@ -1246,7 +1246,7 @@ class tslib_menu {
                        $uid = $mount_info['mount_pid'];
                }
 
-               $recs = $this->sys_page->getMenu($uid,'uid,pid,doktype,mount_pid,mount_pid_ol');
+               $recs = $this->sys_page->getMenu($uid,'uid,pid,doktype,mount_pid,mount_pid_ol,nav_hide');
                foreach($recs as $theRec)       {
                        if (!t3lib_div::inList($this->doktypeExcludeList,$theRec['doktype']) && !$theRec['nav_hide'])   {       // If a menu item seems to be another type than 'Not in menu', then return true (there were items!)
                                return TRUE;
index 14286ed..f8e75e4 100755 (executable)
@@ -823,7 +823,7 @@ class tslib_pibase {
                if (isset($this->LOCAL_LANG[$this->LLkey][$key]))       {
                        $word = $GLOBALS['TSFE']->csConv($this->LOCAL_LANG[$this->LLkey][$key]);
                } elseif (isset($this->LOCAL_LANG['default'][$key]))    {
-                       $word = $this->LOCAL_LANG['default'][$key];
+                       $word = $this->LOCAL_LANG['default'][$key];     // No charset conversion because default is english and thereby ASCII
                } else {
                        $word = $this->LLtestPrefixAlt.$alt;
                }
index ebc744e..3f55d08 100755 (executable)
@@ -90,18 +90,15 @@ class tslib_search {
 
        var $group_by = 'PRIMARY_KEY';                                                  // Alternatively 'PRIMARY_KEY'; sorting by primary key
        var $default_operator = 'AND';                                                  // Standard SQL-operator between words
-       var $operator_translate_table_caseinsensitive = '1';
+       var $operator_translate_table_caseinsensitive = TRUE;
        var $operator_translate_table = Array (                                 // case-sensitiv. Defineres the words, which will be operators between words
                Array ('+' , 'AND'),
+               Array ('|' , 'AND'),
                Array ('-' , 'AND NOT'),
                        // english
-               Array ('AND' , 'AND'),
-               Array ('OR' , 'OR'),
-               Array ('NOT' , 'AND NOT'),
-                       // danish
-               Array ('OG' , 'AND'),
-               Array ('ELLER' , 'OR'),
-               Array ('UDEN' , 'AND NOT')
+               Array ('and' , 'AND'),
+               Array ('or' , 'OR'),
+               Array ('not' , 'AND NOT'),
        );
 
        // Internal
@@ -418,12 +415,12 @@ class tslib_search {
                $op_array = $this->operator_translate_table;
                reset ($op_array);
                if ($this->operator_translate_table_caseinsensitive)    {
-                       $operator = strtoupper($operator);
+                       $operator = strtolower($operator);      // case-conversion is charset insensitive, but it doesn't spoil anything if input string AND operator table is already converted
                }
                while (list($key,$val) = each($op_array))       {
                        $item = $op_array[$key][0];
                        if ($this->operator_translate_table_caseinsensitive)    {
-                               $item = strtoupper($item);
+                               $item = strtolower($item);      // See note above.
                        }
                        if ($operator==$item)   {
                                return $op_array[$key][1];
@@ -463,10 +460,10 @@ class tslib_search {
         * @return      string          URL-parameters with the searchwords
         */
        function get_searchwords()      {
-               $SWORD_PARAMS='';
+               $SWORD_PARAMS = '';
                if (is_array($this->sword_array))       {
                        foreach($this->sword_array as $key => $val)     {
-                               $SWORD_PARAMS.='&sword_list[]='.rawurlencode($val['sword']);
+                               $SWORD_PARAMS.= '&sword_list[]='.rawurlencode($val['sword']);
                        }
                }
                return $SWORD_PARAMS;
@@ -480,7 +477,7 @@ class tslib_search {
        function get_searchwordsArray() {
                if (is_array($this->sword_array))       {
                        foreach($this->sword_array as $key => $val)     {
-                               $swords[]=$val['sword'];
+                               $swords[] = $val['sword'];
                        }
                }
                return $swords;
index 7bcb686..4bbd30b 100755 (executable)
@@ -77,6 +77,8 @@ class tx_indexed_search_extparse {
 
                // This array is configured in initialization:
        var $app = array();
+       var $ext2itemtype_map = array();
+       var $supportedExtensions = array();
 
        var $pObj;              // Reference to parent object (indexer class)
 
@@ -95,6 +97,7 @@ class tx_indexed_search_extparse {
                        // If windows, apply extension to tool name:
                $exe = (TYPO3_OS == 'WIN') ? '.exe' : ''; // lg
                $extOK = FALSE;
+               $mainExtension = '';
 
                        // Ignore extensions
                $ignoreExtensions = t3lib_div::trimExplode(',', strtolower($indexerConfig['ignoreExtensions']),1);
@@ -187,32 +190,39 @@ class tx_indexed_search_extparse {
                                } else $this->pObj->log_setTSlogMessage('unrtf tool (RTF-files) disabled',1);
                        break;
                        case 'txt':             // Raw text
-                       case 'html':    // PHP strip-tags()
-                       case 'htm':             // PHP strip-tags()
                        case 'csv':             // Raw text
                        case 'xml':             // PHP strip-tags()
+                       case 'tif':             // PHP EXIF
+                               $extOK = TRUE;
+                       break;
+                       case 'html':    // PHP strip-tags()
+                       case 'htm':             // PHP strip-tags()
+                               $extOK = TRUE;
+                               $mainExtension = 'html';        // making "html" the common "item_type"
+                       break;
                        case 'jpg':             // PHP EXIF
                        case 'jpeg':    // PHP EXIF
-                       case 'tif':             // PHP EXIF
                                $extOK = TRUE;
+                               $mainExtension = 'jpeg';        // making "jpeg" the common item_type
                        break;
                }
 
                        // If extension was OK:
                if ($extOK)     {
                        $this->supportedExtensions[$extension] = TRUE;
+                       $this->ext2itemtype_map[$extension] = $mainExtension ? $mainExtension : $extension;
                        return TRUE;
                }
        }
 
        /**
         * Initialize external parser for backend modules
-        * Doesn't evaluate if parser is configured right - more like returning POSSIBLE supported extensions (for showing icons etc).
+        * Doesn't evaluate if parser is configured right - more like returning POSSIBLE supported extensions (for showing icons etc) in backend and frontend plugin
         *
         * @param       string          File extension to initialize for.
         * @return      boolean         Returns true if the extension is supported and enabled, otherwise false.
         */
-       function initBackend($extension)        {
+       function softInit($extension)   {
                switch($extension)      {
                        case 'pdf':             // PDF
                        case 'doc':             // MS Word files
@@ -236,6 +246,94 @@ class tx_indexed_search_extparse {
                }
        }
 
+       /**
+        * Return title of entry in media type selector box.
+        *
+        * @param       string          File extension
+        * @return      string          String with label value of entry in media type search selector box (frontend plugin).
+        */
+       function searchTypeMediaTitle($extension)       {
+
+                       // Read indexer-config
+               $indexerConfig = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['indexed_search']);
+
+                       // Ignore extensions
+               $ignoreExtensions = t3lib_div::trimExplode(',', strtolower($indexerConfig['ignoreExtensions']),1);
+               if (in_array($extension, $ignoreExtensions))    {
+                       return FALSE;
+               }
+
+                       // Switch on file extension:
+               switch($extension)      {
+                       case 'pdf':
+                                       // PDF
+                               if ($indexerConfig['pdftools']) {
+                                       return 'PDF';
+                               }
+                       break;
+                       case 'doc':
+                                       // Catdoc
+                               if ($indexerConfig['catdoc'])   {
+                                       return 'MS Word';
+                               }
+                       break;
+                       case 'pps':             // MS PowerPoint(?)
+                       case 'ppt':             // MS PowerPoint
+                                       // ppthtml
+                               if ($indexerConfig['ppthtml'])  {
+                                       return 'MS Powerpoint';
+                               }
+                       break;
+                       case 'xls':             // MS Excel
+                                       // Xlhtml
+                               if ($indexerConfig['xlhtml'])   {
+                                       return 'MS Excel';
+                               }
+                       break;
+                       case 'sxc':             // Open Office Calc.
+                       case 'sxi':             // Open Office Impress
+                       case 'sxw':             // Open Office Writer
+                               if ($indexerConfig['nativeOOMethod'] || $indexerConfig['ruby']) {
+                                       return 'Open Office';
+                               }
+                       break;
+                       case 'rtf':
+                                       // Catdoc
+                               if ($indexerConfig['unrtf'])    {
+                                       return 'RTF';
+                               }
+                       break;
+                       case 'html':    // PHP strip-tags()
+                       case 'jpeg':    // PHP EXIF
+                       case 'txt':             // Raw text
+                       case 'csv':             // Raw text
+                       case 'xml':             // PHP strip-tags()
+                       case 'tif':             // PHP EXIF
+                               return strtoupper($extension);
+                       break;
+                               // NO entry (duplicates or blank):
+                       case 'htm':             // PHP strip-tags()
+                       case 'jpg':             // PHP EXIF
+                       default:
+                       break;
+               }
+       }
+
+       /**
+        * Returns true if the input extension (item_type) is a potentially a multi-page extension
+        *
+        * @param       string          Extension / item_type string
+        * @return      boolean         Return true if multi-page
+        */
+       function isMultiplePageExtension($extension)    {
+                       // Switch on file extension:
+               switch((string)$extension)      {
+                       case 'pdf':
+                               return TRUE;
+                       break;
+               }
+       }
+
 
 
 
index ae63739..f175ee3 100755 (executable)
@@ -920,7 +920,7 @@ class tx_indexedsearch_indexer {
                                        $this->internal_log = array();
                                        $this->log_push('Index: '.str_replace('.','_',basename($file)).($cPKey?'#'.$cPKey:''),'');
                                        $Pstart = t3lib_div::milliseconds();
-                                       $subinfo = array('key' => $cPKey);
+                                       $subinfo = array('key' => $cPKey);      // Setting page range. This is "0" (zero) when no division is made, otherwise a range like "1-3"
                                        $phash_arr = $this->file_phash_arr = $this->setExtHashes($file,$subinfo);
                                        $check = $this->checkMtimeTstamp($mtime, $phash_arr['phash']);
                                        if ($check > 0 || $force)       {
@@ -1386,6 +1386,10 @@ class tx_indexedsearch_indexer {
         */
        function submitFilePage($hash,$file,$subinfo,$ext,$mtime,$ctime,$size,$content_md5h,$contentParts)      {
 
+                       // Find item Type:
+               $storeItemType = $this->external_parsers[$ext]->ext2itemtype_map[$ext];
+               $storeItemType = $storeItemType ? $storeItemType : $ext;
+
                        // Remove any current data for this phash:
                $this->removeOldIndexedFiles($hash['phash']);
 
@@ -1399,7 +1403,7 @@ class tx_indexedsearch_indexer {
                        'cHashParams' => serialize($subinfo),
                        'contentHash' => $content_md5h,
                        'data_filename' => $file,
-                       'item_type' => $ext,
+                       'item_type' => $storeItemType,
                        'item_title' => trim($contentParts['title']) ? $contentParts['title'] : basename($file),
                        'item_description' => $this->bodyDescription($contentParts),
                        'item_mtime' => $mtime,
index 845a81c..2d7bda1 100755 (executable)
@@ -1,3 +1,4 @@
+TIRSDAG:
 - Improve lexer:
        - See BASIC_LEXER from Oracle
        - CJK hack from Zope.
@@ -5,14 +6,52 @@
        - Implement in search query analysis.
 - TESTING with russian, danish, chinese, japanese etc...
 - CVS
+- split search words by new lexer function! (getSearchWords)
 
-**************'
+ONSDAG:
+- Crawler
 
-- Index Configurations / CLI indexer
+
+TORSDAG / FREDAG:
+- Test / Koordinering.
+
+<diverse>
+Search test:
+- "message appears" - viste external media som IKKE var indekseret!?
+- external media respect privacy of pages?
+- external media on multiple pages with DIFFERENT languages?
+- checkResume: Should it also check for gr_list "0,-1"?
+
+Example på alternativ søgning!
+XHTML i frontend?
+
+Backend modules:
 - Proper skinning? / getLL? / XHTML
--------------------------------
+</diverse>
+
+
+
+Test kaniner (indexed search / caching?):
+       - 3DS
+       - Metropol
+       - FI
+       - Link Factory
+       - Brunata
+       - TYPO3.org copy
+
+**************
+getLL with XML-support?
+
 
 CRAWLER:
+Purpose: To request URLs
+Special instructions:
+       - Re-cache
+       - Publish
+       - Index
+       (combinations?)
+       (status data can be stored back in URL-record)
+
 &L=[_TABLE:sys_language;_PID:0:_tx_indexedsearch_fields:bodytext,header]
 &[_LOGIN]=[,kasper,francis;_PID:]
 &myext[uid]=[1-34,35,36-10]&another=1?
@@ -25,31 +64,27 @@ CRAWLER:
        - strlen?
 
 
+***************
+TODO / projects:
+*****************
 
+Documentation:
+- Configuration possibilities (piVars, TypoScript, Hooks etc)
+- How to setup up, analyse and debug indexed search (manual)
+- Technical:
+       - utf-8 internally.
+       - Updates on tables structure
 
-************************************************************
+Statistics module:
+- Someone write a statistics display module for the search operation! (Displaying content from index_stat_search and index_stat_word)
+       Olivier Dobberkau / dkd is on this.
 
-Templating / Display in plugin:
-- Localization, configuration of search-options, stylesheet formatting of result content (with new CSS Stylesheet Editor)
-- Templating
-       - with Template Voila TOs?
-       - other approaches? (markers seem straight forward)
-- linkPage() function
-       - Link correctly to MP links / external documents?
-       - Link correctly to external documents / URLs?
-- CHECK: Which keys are necessary??? There are four keys on typo3.com. Are they all used by the indexer or what?
-- Is result links working for frames? (&type=1) See Message-ID: <3DA762A0.84BDA4F1@kuehn.com>
-- Implement Stop-words in search
-
-Clean up backend modules:
-       - getLL()
-       - skinning()
-       - XHTML()
-
-Misc:
-- DOC: Tutorial on setting it up, getting it to run, trouble shoot it.
-- add possibility of cron-job based crawler-indexing of any external site (based on configuration record in the page tree. Access to that page will determine whether external URL is part of result. Just like the external media is.)
-- flags i pages tabel: set_for_indexing (reset when indexed), do not index, ...
+Various:
+- The checkbox "No Search" in the page header is only respected by indexed_search during indexing! (A page will not be indexed when "No Search" is set). However when searching results are not filtered based on this flag - so if a page is indexed before the no search flag is set it will be found in search results. To change this is hard because the getTreeList() function that fetches all page ids cannot take a where-clause to filter it out but must have hardcoded support. Alternatively the pages table must be joined into the search result so we can select on the field. A solution is still not agreed upon.
 - The Tools>Indexing module could need some shining up and more useful features (Someone else does this?)
-- CLI til removal of old indexes: First set flag, then 14 days later remove the records.
+- CLI script for removal of old indexes: First set flag, then 14 days later remove the records.
 
+Templating / Display in plugin:
+- Templating
+       - with new Template API?
+       - Still need to put a group together.
index 2e70e73..40ac7d7 100755 (executable)
Binary files a/typo3/sysext/indexed_search/doc/manual.sxw and b/typo3/sysext/indexed_search/doc/manual.sxw differ
index d771578..bd9df6c 100755 (executable)
@@ -32,4 +32,18 @@ $TYPO3_CONF_VARS['EXTCONF']['indexed_search']['external_parsers'] = array(
        'tif' => 'EXT:indexed_search/class.external_parser.php:&tx_indexed_search_extparse',
 );
 
+
+       // EXAMPLE configuration of hooks:
+/*
+$TYPO3_CONF_VARS['EXTCONF']['indexed_search']['pi1_hooks'] = array (
+       'initialize_postProc' => 'EXT:indexed_search/example/class.pihook.php:&tx_indexedsearch_pihook',
+       'getResultRows' => 'EXT:indexed_search/example/class.pihook.php:&tx_indexedsearch_pihook',
+       'printResultRow' => 'EXT:indexed_search/example/class.pihook.php:&tx_indexedsearch_pihook',
+       'prepareResultRowTemplateData_postProc' => 'EXT:indexed_search/example/class.pihook.php:&tx_indexedsearch_pihook',
+);
+*/
+
+       // EXAMPLE of adding fields to root line:
+#$TYPO3_CONF_VARS['EXTCONF']['indexed_search']['addRootLineFields']['level3'] = 3;
+
 ?>
\ No newline at end of file
index bcf4e75..f512edb 100755 (executable)
@@ -85,6 +85,7 @@ CREATE TABLE index_section (
   uniqid int(11) DEFAULT '0' NOT NULL auto_increment,
   PRIMARY KEY (uniqid),
   KEY joinkey (phash,rl0),
+#  KEY phash_pid (phash,page_id),
   KEY page_id (page_id),
   KEY rl0 (rl0,rl1,phash),
   KEY rl0_2 (rl0,phash)
index 4eca44f..f6e430f 100755 (executable)
@@ -20,7 +20,7 @@ plugin.tx_indexedsearch {
        lang=0
        desc=0
        results=0
-       
+
 #      defOp.1=1
 #      extResume=1
   }
@@ -31,19 +31,37 @@ plugin.tx_indexedsearch {
   path_stdWrap {
   }
   search {
-    rootPidList = 
+    rootPidList =
     page_links = 10
   }
 
   result_link_target =
-
-  
+/*
+  flagRendering = CASE
+  flagRendering {
+       key.current = 1
+       2 = TEXT
+       2.value = German
+       default = TEXT
+       default.value = English
+  }
+*/
+/*
+  iconRendering = CASE
+  iconRendering {
+       key.current = 1
+       html = TEXT
+       html.value = HtmL
+       default = TEXT
+       default.value = TYPO3 pages
+  }
+*/
   tableParams {
     secHead = border=0 cellpadding=0 cellspacing=0 width="100%"
     searchBox =  border=0 cellpadding=0 cellspacing=0
        searchRes =  border=0 cellpadding=0 cellspacing=0 width="100%"
   }
-  
+
    # Setting default values for piVars (please see the source code for the form-field names which you can preset values for here)
   _DEFAULT_PI_VARS.extResume=1
   _CSS_DEFAULT_STYLE (
@@ -61,7 +79,8 @@ plugin.tx_indexedsearch {
        .tx-indexedsearch .tx-indexedsearch-res .tx-indexedsearch-secHead { margin-top:20px; margin-bottom:5px; }
        .tx-indexedsearch .tx-indexedsearch-res .tx-indexedsearch-secHead H2 { margin-top:0px; margin-bottom:0px; }
        .tx-indexedsearch .tx-indexedsearch-res .tx-indexedsearch-secHead TABLE { background:#cccccc; }
-       .tx-indexedsearch .tx-indexedsearch-res .tx-indexedsearch-secHead TD { vertical-align:absmiddle; }
+       .tx-indexedsearch .tx-indexedsearch-res .tx-indexedsearch-secHead TD { vertical-align:middle; }
+       .tx-indexedsearch .tx-indexedsearch-res .noResume { color : #666666; }
   )
   _LOCAL_LANG {
   }
index 99336e3..aaa2449 100755 (executable)
@@ -29,6 +29,9 @@
  *
  * @author     Kasper Skårhøj <kasperYYYY@typo3.com>
  */
+/**
+ * [CLASS/FUNCTION INDEX of SCRIPT]
+ */
 
 
 unset($MCONF);
@@ -41,9 +44,14 @@ t3lib_extMgm::isLoaded("indexed_search",1);
 require_once(t3lib_extMgm::extPath('indexed_search').'class.indexer.php');
 
 
-// ***************************
-// Script Classes
-// ***************************
+
+/**
+ * Backend module providing boring statistics of the index-tables.
+ *
+ * @author     Kasper Skaarhoj <kasperYYYY@typo3.com>
+ * @package TYPO3
+ * @subpackage tx_indexedsearch
+ */
 class SC_mod_tools_isearch_index {
        var $MCONF=array();
        var $MOD_MENU=array();
@@ -53,6 +61,9 @@ class SC_mod_tools_isearch_index {
        var $include_once=array();
        var $content;
 
+       /**
+        * Initialization
+        */
        function init() {
                global $BE_USER,$LANG,$BACK_PATH,$TCA_DESCR,$TCA,$CLIENT,$TYPO3_CONF_VARS;
                $this->MCONF = $GLOBALS["MCONF"];
@@ -138,9 +149,23 @@ class SC_mod_tools_isearch_index {
        }
 
 
-       // ***************************
-       // OTHER FUNCTIONS:
-       // ***************************
+
+
+
+
+
+
+
+
+       /***************************
+        *
+        * OTHER FUNCTIONS:
+        *
+        ***************************/
+
+       /**
+        *
+        */
        function getRecordsNumbers()    {
                $tables=explode(",","index_phash,index_words,index_rel,index_grlist,index_section,index_fulltext");
                $recList=array();
index 0d85e69..0a042d7 100755 (executable)
@@ -177,7 +177,7 @@ class tx_indexedsearch_modfunc1 extends t3lib_extobjbase {
                                $this->external_parsers[$extension] = &t3lib_div::getUserObj($_objRef);
 
                                        // Init parser and if it returns false, unset its entry again:
-                               if (!$this->external_parsers[$extension]->initBackend($extension))      {
+                               if (!$this->external_parsers[$extension]->softInit($extension)) {
                                        unset($this->external_parsers[$extension]);
                                }
                        }
@@ -1133,10 +1133,10 @@ class tx_indexedsearch_modfunc1 extends t3lib_extobjbase {
                        if ($fullPath)  {
                                $info = @getimagesize($fullPath);
                                $iconPath = $GLOBALS['BACK_PATH'].'../'.substr($fullPath,strlen(PATH_site));
-                               $this->iconFileNameCache[$it] = is_array($info) ? '<img src="'.$iconPath.'" '.$info[3].' title="'.htmlspecialchars($alt).'" alt="" />' : '';
+                               $this->iconFileNameCache[$it] = is_array($info) ? '<img src="'.$iconPath.'" '.$info[3].' title="###TITLE_ATTRIBUTE###" alt="" />' : '';
                        }
                }
-               return $this->iconFileNameCache[$it];
+               return str_replace('###TITLE_ATTRIBUTE###',htmlspecialchars($it.': '.$alt),$this->iconFileNameCache[$it]);
        }
 
        /**
@@ -1310,6 +1310,7 @@ class tx_indexedsearch_modfunc1 extends t3lib_extobjbase {
                                                        $indexerObj->backend_initIndexer($this->pObj->id, 0, 0, '', $rl, $GETparams, $cfgRow['chashcalc'] ? TRUE : FALSE);
                                                        $indexerObj->backend_setFreeIndexUid($cfgRow['uid']);
 
+                                                       $theContent = '';
                                                        foreach($fieldList as $k => $v) {
                                                                if (!$k)        {
                                                                        $theTitle = $r[$v];
@@ -1317,6 +1318,7 @@ class tx_indexedsearch_modfunc1 extends t3lib_extobjbase {
                                                                        $theContent.= $r[$v].' ';
                                                                }
                                                        }
+debug($theContent,$theTitle);
                                                        $indexerObj->backend_indexAsTYPO3Page(
                                                                        $theTitle,
                                                                        '',
index 162db1b..eb3870d 100755 (executable)
  * @author     Kasper Skårhøj <kasperYYYY@typo3.com>
  * @co-author  Christian Jul Jensen <christian@typo3.com>
  */
+/**
+ * [CLASS/FUNCTION INDEX of SCRIPT]
+ *
+ *
+ *
+ *  120: class tx_indexedsearch extends tslib_pibase
+ *  164:     function main($content, $conf)
+ *  197:     function initialize()
+ *  374:     function getSearchWords($defOp)
+ *
+ *              SECTION: Main functions
+ *  418:     function doSearch($sWArr)
+ *  451:     function getResultRows($sWArr)
+ *  521:     function getResultRows_SQLpointer($sWArr)
+ *  541:     function getDisplayResults($sWArr, $resData)
+ *  592:     function compileResult($resultRows)
+ *
+ *              SECTION: Searching functions (SQL)
+ *  685:     function getPhashList($sWArr)
+ *  786:     function execPHashListQuery($wordSel,$plusQ='')
+ *  806:     function sectionTableWhere()
+ *  853:     function mediaTypeWhere()
+ *  878:     function languageWhere()
+ *  890:     function execFinalQuery($list)
+ * 1028:     function checkResume($row)
+ * 1075:     function isDescending($inverse=FALSE)
+ * 1089:     function writeSearchStat($sWArr,$count,$pt)
+ *
+ *              SECTION: HTML output functions
+ * 1140:     function makeSearchForm($optValues)
+ * 1212:     function printRules()
+ * 1228:     function printResultSectionLinks()
+ * 1250:     function makeSectionHeader($id,$sectionTitleLinked,$countResultRows)
+ * 1266:     function printResultRow($row, $headerOnly=0)
+ * 1341:     function pi_list_browseresults($showResultCount=1,$addString='',$addPart='')
+ *
+ *              SECTION: Support functions for HTML output (with a minimum of fixed markup)
+ * 1404:     function prepareResultRowTemplateData($row, $headerOnly)
+ * 1448:     function tellUsWhatIsSeachedFor($sWArr)
+ * 1482:     function wrapSW($str)
+ * 1494:     function renderSelectBox($name,$value,$optValues)
+ * 1517:     function makePointerSelector_link($str,$p)
+ * 1530:     function makeItemTypeIcon($it,$alt='',$specRowConf)
+ * 1572:     function makeRating($row)
+ * 1617:     function makeDescription($row,$noMarkup=0,$lgd=180)
+ * 1643:     function markupSWpartsOfString($str)
+ * 1713:     function makeTitle($row)
+ * 1737:     function makeInfo($row,$tmplArray)
+ * 1755:     function getSpecialConfigForRow($row)
+ * 1779:     function makeLanguageIndication($row)
+ * 1816:     function makeAccessIndication($id)
+ * 1830:     function linkPage($id,$str,$row=array())
+ * 1873:     function getRootLine($id,$pathMP='')
+ * 1888:     function getFirstSysDomainRecordForPage($id)
+ * 1901:     function getPathFromPageId($id,$pathMP='')
+ * 1953:     function getMenu($id)
+ * 1972:     function multiplePagesType($item_type)
+ * 1982:     function utf8_to_currentCharset($str)
+ * 1992:     function &hookRequest($functionName)
+ *
+ * TOTAL FUNCTIONS: 45
+ * (This index is automatically created/updated by the extension "extdeveval")
+ *
+ */
 
 
 
+require_once(PATH_tslib.'class.tslib_pibase.php');
+require_once(PATH_tslib.'class.tslib_search.php');
+require_once(t3lib_extMgm::extPath('indexed_search').'class.indexer.php');
 
-require_once(PATH_tslib."class.tslib_pibase.php");
-require_once(PATH_tslib."class.tslib_search.php");
-require_once(t3lib_extMgm::extPath("indexed_search")."class.indexer.php");
 
+/**
+ * Index search frontend
+ *
+ * Creates a searchform for indexed search. Indexing must be enabled
+ * for this to make sense.
+ *
+ * @package TYPO3
+ * @subpackage tx_indexedsearch
+ * @author     Kasper Skårhøj <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 $join_pages=0;      // See document for info about this flag...
-
-       var $defaultResultNumber=20;
-       var $wholeSiteIdList = 0;
-
-       var $operator_translate_table = Array (         // case-sensitiv. Defineres the words, which will be operators between words
-               Array ("+" , "AND"),
-               Array ("|" , "OR"),
-               Array ("-" , "AND NOT"),
+    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 $operator_translate_table = Array (         // case-sensitive. Defines the words, which will be operators between words
+               Array ('+' , 'AND'),
+               Array ('|' , 'OR'),
+               Array ('-' , 'AND NOT'),
                        // english
-#              Array ("AND" , "AND"),
-#              Array ("OR" , "OR"),
-#              Array ("NOT" , "AND NOT"),
+#              Array ('AND' , 'AND'),
+#              Array ('OR' , 'OR'),
+#              Array ('NOT' , 'AND NOT'),
        );
 
+               // Internal variable
+       var $wholeSiteIdList = 0;               // Root-page PIDs to search in (rl0 field where clause, see initialize() function)
+
                // Internals:
-       var $cache_path=array();
-       var $cache_rl=array();
-       var $fe_groups_required=array();
-       var $domain_records=array();
-       var $sWArr=array();
-       var $wSelClauses=array();
-       var $firstRow=array();
-       var $resultSections=array();
-
-       var $anchorPrefix = '';                 // Prefix for local anchors. For "speaking URLs" to work with <base>-url set.
-
-    function main($content,$conf)    {
-        $this->conf=$conf;
+       var $sWArr = array();                   // Search Words and operators
+       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....
+
+
+
+       /**
+        * Main function, called from TypoScript as a USER_INT object.
+        *
+        * @param       string          Content input, ignore (just put blank string)
+        * @param       array           TypoScript configuration of the plugin!
+        * @return      string          HTML code for the search form / result display.
+        */
+       function main($content, $conf)    {
+
+                       // Initialize:
+        $this->conf = $conf;
         $this->pi_loadLL();
                $this->pi_setPiVarDefaults();
-               $this->anchorPrefix = substr(t3lib_div::getIndpEnv('TYPO3_REQUEST_URL'),strlen(t3lib_div::getIndpEnv('TYPO3_SITE_URL')));
-
-#debug($this->piVars);
 
                        // Initialize the indexer-class - just to use a few function (for making hashes)
-               $this->indexerObj = t3lib_div::makeInstance("tx_indexedsearch_indexer");
+               $this->indexerObj = t3lib_div::makeInstance('tx_indexedsearch_indexer');
+
+                       // Initialize:
+               $this->initialize();
+
+                       // Do search:
+                       // If there were any search words entered...
+               if (is_array($this->sWArr))     {
+                       $content = $this->doSearch($this->sWArr);
+               }
+
+                       // Finally compile all the content, form, messages and results:
+        $content=
+                       $this->makeSearchForm($this->optValues).
+                       $this->printRules().
+           $content;
+
+        return $this->pi_wrapInBaseClass($content);
+    }
+
+       /**
+        * Initialize internal variables, especially selector box values for the search form and search words
+        *
+        * @return      void
+        */
+       function initialize()   {
+               global $TYPO3_CONF_VARS;
+
+                       // 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)    {
+                               $this->external_parsers[$extension] = &t3lib_div::getUserObj($_objRef);
+
+                                       // Init parser and if it returns false, unset its entry again:
+                               if (!$this->external_parsers[$extension]->softInit($extension)) {
+                                       unset($this->external_parsers[$extension]);
+                               }
+                       }
+               }
 
                        // If "_sections" is set, this value overrides any existing value.
-               if ($this->piVars["_sections"])         $this->piVars["sections"] = $this->piVars["_sections"];
+               if ($this->piVars['_sections'])         $this->piVars['sections'] = $this->piVars['_sections'];
 
                        // 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"];
+               if ($this->piVars['sword_prev_include'] && $this->piVars['sword_prev']) {
+                       $this->piVars['sword'] = trim($this->piVars['sword_prev']).' '.$this->piVars['sword'];
                }
 
+               $this->piVars['results'] = t3lib_div::intInRange($this->piVars['results'],1,100000,$this->defaultResultNumber);
+
                        // Selector-box values defined here:
-               $optValues = Array(
-                       "type" => Array(
-                               "0" => $this->pi_getLL("opt_type_0"),
-                               "1" => $this->pi_getLL("opt_type_1"),
-                               "2" => $this->pi_getLL("opt_type_2"),
-                               "3" => $this->pi_getLL("opt_type_3"),
-                               "10" => $this->pi_getLL("opt_type_10"),
-                               "20" => $this->pi_getLL("opt_type_20"),
+               $this->optValues = Array(
+                       'type' => Array(
+                               '0' => $this->pi_getLL('opt_type_0'),
+                               '1' => $this->pi_getLL('opt_type_1'),
+                               '2' => $this->pi_getLL('opt_type_2'),
+                               '3' => $this->pi_getLL('opt_type_3'),
+                               '10' => $this->pi_getLL('opt_type_10'),
+                               '20' => $this->pi_getLL('opt_type_20'),
                        ),
-                       "defOp" => Array(
-                               "0" => $this->pi_getLL("opt_defOp_0"),
-                               "1" => $this->pi_getLL("opt_defOp_1"),
+                       'defOp' => Array(
+                               '0' => $this->pi_getLL('opt_defOp_0'),
+                               '1' => $this->pi_getLL('opt_defOp_1'),
                        ),
-                       "sections" => Array(
-                               "0" => $this->pi_getLL("opt_sections_0"),
-                               "-1" => $this->pi_getLL("opt_sections_-1"),
-                               "-2" => $this->pi_getLL("opt_sections_-2"),
-                               "-3" => $this->pi_getLL("opt_sections_-3"),
+                       'sections' => Array(
+                               '0' => $this->pi_getLL('opt_sections_0'),
+                               '-1' => $this->pi_getLL('opt_sections_-1'),
+                               '-2' => $this->pi_getLL('opt_sections_-2'),
+                               '-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.
                        ),
-                       "media" => Array(
-                               "-1" => $this->pi_getLL("opt_media_-1"),
-                               "0" => $this->pi_getLL("opt_media_0"),
-                               "-2" => $this->pi_getLL("opt_media_-2"),
-                               "1" => $this->pi_getLL("opt_media_1"),
-                               "2" => $this->pi_getLL("opt_media_2"),
-                               "3" => $this->pi_getLL("opt_media_3"),
+                       'media' => Array(
+                               '-1' => $this->pi_getLL('opt_media_-1'),
+                               '0' => $this->pi_getLL('opt_media_0'),
+                               '-2' => $this->pi_getLL('opt_media_-2'),
                        ),
-                       "order" => Array(
-                               "rank_flag" => $this->pi_getLL("opt_order_rank_flag"),
-                               "rank_freq" => $this->pi_getLL("opt_order_rank_freq"),
-                               "rank_first" => $this->pi_getLL("opt_order_rank_first"),
-                               "rank_count" => $this->pi_getLL("opt_order_rank_count"),
-                               "mtime" => $this->pi_getLL("opt_order_mtime"),
-                               "title" => $this->pi_getLL("opt_order_title"),
-                               "crdate" => $this->pi_getLL("opt_order_crdate"),
-#                              "rating" => "Page-rating",
-#                              "hits" => "Page-hits",
+                       'order' => Array(
+                               'rank_flag' => $this->pi_getLL('opt_order_rank_flag'),
+                               'rank_freq' => $this->pi_getLL('opt_order_rank_freq'),
+                               'rank_first' => $this->pi_getLL('opt_order_rank_first'),
+                               'rank_count' => $this->pi_getLL('opt_order_rank_count'),
+                               'mtime' => $this->pi_getLL('opt_order_mtime'),
+                               'title' => $this->pi_getLL('opt_order_title'),
+                               'crdate' => $this->pi_getLL('opt_order_crdate'),
                        ),
-                       "group" => Array (
-                               "sections" => $this->pi_getLL("opt_group_sections"),
-                               "flat" => $this->pi_getLL("opt_group_flat"),
+                       'group' => Array (
+                               'sections' => $this->pi_getLL('opt_group_sections'),
+                               'flat' => $this->pi_getLL('opt_group_flat'),
                        ),
-                       "lang" => Array (
-                               -1 => $this->pi_getLL("opt_lang_-1"),
-                               0 => $this->pi_getLL("opt_lang_0"),
+                       'lang' => Array (
+                               -1 => $this->pi_getLL('opt_lang_-1'),
+                               0 => $this->pi_getLL('opt_lang_0'),
                        ),
-                       "desc" => Array (
-                               "0" => $this->pi_getLL("opt_desc_0"),
-                               "1" => $this->pi_getLL("opt_desc_1"),
+                       'desc' => Array (
+                               '0' => $this->pi_getLL('opt_desc_0'),
+                               '1' => $this->pi_getLL('opt_desc_1'),
                        ),
-                       "results" => Array (
-                               "10" => "10",
-                               "20" => "20",
-                               "50" => "50",
-                               "100" => "100",
+                       'results' => Array (
+                               '10' => '10',
+                               '20' => '20',
+                               '50' => '50',
+                               '100' => '100',
                        )
                );
 
-               $this->operator_translate_table[]=Array ($this->pi_getLL("local_operator_AND") , "AND");
-               $this->operator_translate_table[]=Array ($this->pi_getLL("local_operator_OR") , "OR");
-               $this->operator_translate_table[]=Array ($this->pi_getLL("local_operator_NOT") , "AND NOT");
+                       // Add media to search in:
+               foreach($this->external_parsers as $extension => $obj)  {
+                       if ($name = $obj->searchTypeMediaTitle($extension))     {
+                               $this->optValues['media'][$extension] = $this->pi_getLL('opt_sections_'.$extension,$name);
+                       }
+               }
+
+                       // Add operators for various languages
+                       // Converts the operators to UTF-8 and lowercase
+               $this->operator_translate_table[] = Array($GLOBALS['TSFE']->csConvObj->conv_case('utf-8',$GLOBALS['TSFE']->csConvObj->utf8_encode($this->pi_getLL('local_operator_AND'), $GLOBALS['TSFE']->renderCharset),'toLower') , 'AND');
+               $this->operator_translate_table[] = Array($GLOBALS['TSFE']->csConvObj->conv_case('utf-8',$GLOBALS['TSFE']->csConvObj->utf8_encode($this->pi_getLL('local_operator_OR'), $GLOBALS['TSFE']->renderCharset),'toLower') , 'OR');
+               $this->operator_translate_table[] = Array($GLOBALS['TSFE']->csConvObj->conv_case('utf-8',$GLOBALS['TSFE']->csConvObj->utf8_encode($this->pi_getLL('local_operator_NOT'), $GLOBALS['TSFE']->renderCharset),'toLower') , 'AND NOT');
 
                        // This is the id of the site root. This value may be a commalist of integer (prepared for this)
-               $this->wholeSiteIdList=intval($GLOBALS["TSFE"]->config["rootLine"][0]["uid"]);
+               $this->wholeSiteIdList = intval($GLOBALS['TSFE']->config['rootLine'][0]['uid']);
 
+                       // Creating levels for section menu:
                        // This selects the first and secondary menus for the "sections" selector - so we can search in sections and sub sections.
-               if ($this->conf["show."]["L1sections"]) {
+               if ($this->conf['show.']['L1sections']) {
                        $firstLevelMenu = $this->getMenu($this->wholeSiteIdList);
-       #               debug($firstLevelMenu);
-                       while(list($kk,$mR)=each($firstLevelMenu))      {
-                               if ($mR["doktype"]!=5)  {
-                                       $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)  {
-                                                               $optValues["sections"]["rl2_".$mR2["uid"]]=trim($this->pi_getLL("opt_RL2")." ".$mR2["title"]);
+                       while(list($kk,$mR) = each($firstLevelMenu))    {
+                               if ($mR['doktype']!=5)  {
+                                       $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)  {
+                                                               $this->optValues['sections']['rl2_'.$mR2['uid']] = trim($this->pi_getLL('opt_RL2').' '.$mR2['title']);
                                                        } else unset($secondLevelMenu[$kk2]);
                                                }
-                                               $optValues["sections"]["rl2_".implode(",",array_keys($secondLevelMenu))]=$this->pi_getLL("opt_RL2ALL");
+                                               $this->optValues['sections']['rl2_'.implode(',',array_keys($secondLevelMenu))] = $this->pi_getLL('opt_RL2ALL');
                                        }
                                } else unset($firstLevelMenu[$kk]);
                        }
-                       $optValues["sections"]["rl1_".implode(",",array_keys($firstLevelMenu))]=$this->pi_getLL("opt_RL1ALL");
+                       $this->optValues['sections']['rl1_'.implode(',',array_keys($firstLevelMenu))] = $this->pi_getLL('opt_RL1ALL');
                }
 
+                       // Setting the list of root PIDs for the search. Notice, these page IDs MUST have a TypoScript template with root flag on them! Basically this list is used to select on the "rl0" field and page ids are registered as "rl0" only if a TypoScript template record with root flag is there.
                        // This happens AFTER the use of $this->wholeSiteIdList above because the above will then fetch the menu for the CURRENT site - regardless of this kind of searching here. Thus a general search will lookup in the WHOLE database while a specific section search will take the current sections...
-               if ($this->conf["search."]["rootPidList"])      {
-                       $this->wholeSiteIdList = implode(",",t3lib_div::intExplode(",",$this->conf["search."]["rootPidList"]));
-#debug($this->wholeSiteIdList);
+               if ($this->conf['search.']['rootPidList'])      {
+                       $this->wholeSiteIdList = implode(',',t3lib_div::intExplode(',',$this->conf['search.']['rootPidList']));
                }
 
-
                        // 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))        {
-                       $optValues["lang"][$lR["uid"]]=$lR["title"];
+                       $this->optValues['lang'][$lR['uid']] = $lR['title'];
                }
 
+                       // Calling hook for modification of initialized content
+               if ($hookObj = &$this->hookRequest('initialize_postProc'))      {
+                       $hookObj->initialize_postProc();
+               }
 
-
-#debug($this->piVars);
+                       // Default values set:
                        // Setting first values in optValues as default values IF there is not corresponding piVar value set already.
-               reset($optValues);
-               while(list($kk,$vv)=each($optValues))   {
+               foreach($this->optValues as $kk => $vv) {
                        if (!isset($this->piVars[$kk])) {
                                reset($vv);
-                               $this->piVars[$kk]=key($vv);
+                               $this->piVars[$kk] = key($vv);
                        }
                }
-#debug($this->piVars);
 
                        // Blind selectors:
-               if (is_array($this->conf["blind."]))    {
-                       reset($this->conf["blind."]);
-                       while(list($kk,$vv)=each($this->conf["blind."]))        {
+               if (is_array($this->conf['blind.']))    {
+                       foreach($this->conf['blind.'] as $kk => $vv)    {
                                if (is_array($vv))      {
-                                       reset($vv);
-                                       while(list($kkk,$vvv)=each($vv))        {
-                                               if (!is_array($vvv) && $vvv && is_array($optValues[substr($kk,0,-1)]))  {
-                                                       unset($optValues[substr($kk,0,-1)][$kkk]);
+                                       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]);
                                                }
                                        }
                                } elseif ($vv) {        // If value is not set, unset the option array.
-                                       unset($optValues[$kk]);
+                                       unset($this->optValues[$kk]);
                                }
                        }
                }
 
-
                        // This gets the search-words into the $sWArr:
-               $this->sWArr = $sWArr = $this->getSearchWords($this->piVars["defOp"]);
-#debug($this->sWArr);
+               $this->sWArr = $this->getSearchWords($this->piVars['defOp']);
+       }
+
+       /**
+        * Splits the search word input into an array where each word is represented by an array with key "sword" holding the search word and key "oper" holds the SQL operator (eg. AND, OR)
+        *
+        * Only words with 2 or more characters are accepted
+        * Max 200 chars total
+        * Space is used to split words, "" can be used search for a whole string (not indexed search then)
+        * AND, OR and NOT are prefix words, overruling the default operator
+        * +/|/- equals AND, OR and NOT as operators.
+        * All search words are converted to lowercase.
+        *
+        * $defOp is the default operator. 1=OR, 0=AND
+        *
+        * @param       boolean         If true, the default operator will be OR, not AND
+        * @return      array           Returns array with search words if any found
+        */
+       function getSearchWords($defOp) {
+
+                       // Shorten search-word string to max 200 bytes (does NOT take multibyte charsets into account - but never mind, shortening the string here is only a run-away feature!)
+               $inSW = substr($this->piVars['sword'],0,200);
+
+                       // Convert to UTF-8:
+               $inSW = $GLOBALS['TSFE']->csConvObj->utf8_encode($inSW, $GLOBALS['TSFE']->metaCharset);
+
+               if ($this->piVars['type']==20)  {
+                       return array(array('sword'=>trim($inSW), 'oper'=>'AND'));
+               } else {
+                       $search = t3lib_div::makeInstance('tslib_search');
+                       $search->default_operator = $defOp==1 ? 'OR' : 'AND';
+                       $search->operator_translate_table = $this->operator_translate_table;
+                       $search->register_and_explode_search_string($inSW);
+
+                       if (is_array($search->sword_array))     {
+                               return $search->sword_array;
+                       }
+               }
+       }
+
 
-                       // If there was any search words entered...
-               if (is_array($sWArr))   {
-                       $content = $this->doSearch($sWArr);
-               }       // END: There was a search word.
 
-                       // Finally compile all the content, form, messages and results:
-        $content=
-                       $this->makeSearchForm($optValues).
-                       $this->printRules().
-           $content;
 
-        return $this->pi_wrapInBaseClass($content);
-    }
+
+
+
+
+
+
+
+       /*****************************
+        *
+        * Main functions
+        *
+        *****************************/
 
        /**
-        * Performs the search, if any search words found.
+        * Performs the search, the display and writing stats
+        *
+        * @param       array           Search words in array, see ->getSearchWords() for details
+        * @return      string          HTML for result display.
         */
        function doSearch($sWArr)       {
-               $rowcontent="";
-               $pt1=t3lib_div::milliseconds();
 
-                       // This SEARCHES for the searchwords in $sWArr AND returns a COMPLETE list of phash-integers of the matches.
-               $list = $this->getPhashList($sWArr);
-               $pt2=t3lib_div::milliseconds();
+                       // Get result rows:
+               $pt1 = t3lib_div::milliseconds();
+               if ($hookObj = &$this->hookRequest('getResultRows'))    {
+                       $resData = $hookObj->getResultRows($sWArr);
+               } else {
+                       $resData = $this->getResultRows($sWArr);
+               }
 
+                       // Display search results:
+               $pt2 = t3lib_div::milliseconds();
+               if ($hookObj = &$this->hookRequest('getDisplayResults'))        {
+                       $content = $hookObj->getDisplayResults($sWArr, $resData);
+               } else {
+                       $content = $this->getDisplayResults($sWArr, $resData);
+               }
 
-                       // IF there were any matches (there is results...) then go on.
-               if ($list)      {
-                       $GLOBALS["TT"]->push("Searching Final result");
+               $pt3 = t3lib_div::milliseconds();
 
-                               // Do the search:
-                       $res = $this->execFinalQuery($list);
+                       // Write search statistics
+               $this->writeSearchStat($sWArr,$resData['count'],array($pt1,$pt2,$pt3));
+
+                       // Return content:
+               return $content;
+       }
+
+       /**
+        * Get search result rows / data from database. Returned as data in array.
+        *
+        * @param       array           Search word array
+        * @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)  {
+
+                       // Getting SQL result pointer:
+                       $GLOBALS['TT']->push('Searching result');
+               $res = $this->getResultRows_SQLpointer($sWArr);
+                       $GLOBALS['TT']->pull();
+
+                       // Organize and process result:
+               if ($res)       {
 
                                // Get some variables:
                        $count = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
-#debug($count);
-                       $this->piVars["results"] = $displayCount = t3lib_div::intInRange($this->piVars["results"],1,100000,$this->defaultResultNumber);
-                       $pointer=t3lib_div::intInRange($this->piVars["pointer"],0,floor($count/$displayCount));
+                       $pointer = t3lib_div::intInRange($this->piVars['pointer'],0,floor($count/$this->piVars['results']));
 
-                       $pt3=t3lib_div::milliseconds();
+                               // Initialize result accumulation variables:
+                       $c = 0;
+                       $lines = Array();
+                       $grouping_phashes = array();    // Used to filter out duplicates.
+                       $grouping_chashes = array();    // Used to filter out duplicates BASED ON cHash.
+                       $firstRow = Array();            // Will hold the first row in result - used to calculate relative hit-ratings.
+                       $resultRows = Array();  // Will hold the results rows for display.
 
                                // Now, traverse result and put the rows to be displayed into an array
-                       $lines=Array();
-                       $c=0;
-                       $this->firstRow=Array();        // Will hold the first row in result - used to calculate relative hit-ratings.
-                       $this->resultRows=Array();      // Will hold the results rows for display.
-                       $this->grouping_phashes=array();        // Used to filter out duplicates.
-                       $this->grouping_chashes=array();        // Used to filter out duplicates BASED ON cHash.
+                               // Each row should be a the fields from 'ISEC.*, IP.*' combined + artificial fields "show_resume" (boolean) and "result_number" (counter)
                        while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))       {
+
+                                       // Set first row:
                                if (!$c)        {
-                                       $this->firstRow=$row;
+                                       $firstRow = $row;
                                }
 
-                               $row["show_resume"]=$this->checkResume($row);
-                               $phashGr = !in_array($row["phash_grouping"],$this->grouping_phashes);
-                               $chashGr = !in_array($row["contentHash"].".".$row["data_page_id"],$this->grouping_chashes);
+                               $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["item_type"]!=2)       {       // Only on documents which are not PDF files.
-                                                       $this->grouping_phashes[]=$row["phash_grouping"];
+                                       if ($row['show_resume'])        {       // 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'];
                                                }
-                                               $this->grouping_chashes[]=$row["contentHash"].".".$row["data_page_id"];
+                                               $grouping_chashes[] = $row['contentHash'].'.'.$row['data_page_id'];
                                        }
                                        $c++;
 
                                                // All rows for display is put into resultRows[]
-                                       if ($c > $pointer*$displayCount)        {
-                                               $row["result_number"]=$c;
-                                               $this->resultRows[] = $row;
-                                               if ($c+1 > ($pointer+1)*$displayCount)  break;
+                                       if ($c > $pointer * $this->piVars['results'])   {
+                                               $row['result_number'] = $c;
+                                               $resultRows[] = $row;
+                                               if ($c+1 > ($pointer+1)*$this->piVars['results'])       break;
                                        }
                                } 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.
-#                                      debug();
                                }
                        }
-                       $GLOBALS["TT"]->pull();
 
-#debug($this->resultRows);
-#debug(count($this->resultRows));
-#debug($this->grouping_chashes);
+                       return array(
+                                               'resultRows' => $resultRows,
+                                               'firstRow' => $firstRow,
+                                               'count' => $count
+                                       );
+               } else {        // No results found:
+                       return FALSE;
+               }
+       }
+
+       /**
+        * Gets a SQL result pointer to traverse for the search records.
+        *
+        * @param       array           Search words
+        * @return      pointer
+        */
+       function getResultRows_SQLpointer($sWArr)       {
+                               // This SEARCHES for the searchwords in $sWArr AND returns a COMPLETE list of phash-integers of the matches.
+               $list = $this->getPhashList($sWArr);
 
-                       $GLOBALS["TT"]->push("Display Final result");
+                       // Perform SQL Search / collection of result rows array:
+               if ($list)      {
+                               // Do the search:
+                       return $this->execFinalQuery($list);
+               } else {
+                       return FALSE;
+               }
+       }
 
-                               // SO, on to the result display here:
-                       $rowcontent.=$this->compileResult($this->resultRows);
-                       $pt4=t3lib_div::milliseconds();
+       /**
+        * Compiles the HTML display of the incoming array of result rows.
+        *
+        * @param       array           Search words array (for display of text describing what was searched for)
+        * @param       array           Array with result rows, count, first row.
+        * @return      string          HTML content to display result.
+        */
+       function getDisplayResults($sWArr, $resData)    {
+                       // Perform display of result rows array:
+               if ($resData)   {
+                       $GLOBALS['TT']->push('Display Final result');
 
-                               // Makes the result browsing navigation (next/prev, 1-2-3)
-#                      $PS = $this->makePointerSelector($count,$displayCount,$pointer);
+                               // Set first selected row (for calculation of ranking later)
+                       $this->firstRow = $resData['firstRow'];
 
+                               // Result display here:
+                       $rowcontent = '';
+                       $rowcontent.= $this->compileResult($resData['resultRows']);
 
                                // Browsing box:
-                       if ($count)     {
-                               #$content.=$PS."<HR>";
-                               $this->internal["res_count"]=$count;
-                               $this->internal["results_at_a_time"]=$displayCount;
-                               $this->internal["maxPages"]=t3lib_div::intInRange($this->conf["search."]["page_links"],1,100,10);
-                               $addString = ($count&&$this->piVars["group"]=="sections"?" ".sprintf($this->pi_getLL("inNsection".(count($this->resultSections)>1?"s":"")),count($this->resultSections)):"");
+                       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);
                        }
 
-                               // Print the time the search took:
-                       if ($pt1 && $this->conf["show."]["parsetimes"]) {
-                               $parsetimes="";
-                               $parsetimes.="<p>Word Search took: ".($pt2-$pt1)." ms<BR>";
-                               $parsetimes.="Order Search took: ".($pt3-$pt2)." ms<BR>";
-                               $parsetimes.="Display took: ".($pt4-$pt3)." ms</p><HR>";
-                       }
-
                                // Browsing nav, bottom.
-                       if ($count)     {
-                               $content=$browseBox1.$rowcontent.$browseBox2;
+                       if ($resData['count'])  {
+                               $content = $browseBox1.$rowcontent.$browseBox2;
                        } else {
-                               $content='<p'.$this->pi_classParam("noresults").'>'.$this->pi_getLL("noResults").'</p>';
+                               $content = '<p'.$this->pi_classParam('noresults').'>'.$this->pi_getLL('noResults','',1).'</p>';
                        }
-                       $content.=$parsetimes;
 
-                       $GLOBALS["TT"]->pull();
-               } else {        // No results found:
-                       $content.='<p'.$this->pi_classParam("noresults").'>'.$this->pi_getLL("noResults").'</p>';
+                       $GLOBALS['TT']->pull();
+               } else {
+                       $content.='<p'.$this->pi_classParam('noresults').'>'.$this->pi_getLL('noResults','',1).'</p>';
                }
 
                        // 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")." '".substr($this->getPathFromPageId(substr($this->piVars["sections"],4)),1)."'":"");
-               $what='<div'.$this->pi_classParam("whatis").'><p>'.$what.'</p></div>';
-               $content=$what.$content;
+               $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>';
+               $content = $what.$content;
 
-                       // Write search statistics
-               $this->writeSearchStat($sWArr,$count,array($pt1,$pt2,$pt3,$pt4));
+                       // Return content:
                return $content;
        }
 
+       /**
+        * Takes the array with resultrows as input and returns the result-HTML-code
+        * Takes the "group" var into account: Makes a "section" or "flat" display.
+        *
+        * @param       array           Result rows
+        * @return      string          HTML
+        */
+       function compileResult($resultRows)     {
+               $content = '';
 
+                       // Transfer result rows to new variable, performing some mapping of sub-results etc.
+               $newResultRows = array();
+               foreach($resultRows as $row)    {
+                       $id = md5($row['phash_grouping']);
+                       if (is_array($newResultRows[$id]))      {
+                               if (!$newResultRows[$id]['show_resume'] && $row['show_resume']) {       // swapping:
 
+                                               // Remove old
+                                       $subrows = $newResultRows[$id]['_sub'];
+                                       unset($newResultRows[$id]['_sub']);
+                                       $subrows[] = $newResultRows[$id];
 
+                                               // Insert new:
+                                       $newResultRows[$id] = $row;
+                                       $newResultRows[$id]['_sub'] = $subrows;
+                               } else $newResultRows[$id]['_sub'][] = $row;
+                       } else {
+                               $newResultRows[$id] = $row;
+                       }
+               }
+               $resultRows = $newResultRows;
 
 
-       /***********************************
+               switch($this->piVars['group'])  {
+                       case 'sections':
 
-               SEARCHING FUNCTIONS
+                               $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();
+
+                               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 = 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));
+
+                                               // Add content header:
+                                       $content.= $this->makeSectionHeader($id,$sectionTitleLinked,count($resultRows));
+
+                                               // Render result rows:
+                                       foreach($resultRows as $row)    {
+                                               $content.= $this->printResultRow($row);
+                                       }
+                               }
+                       break;
+                       default:        // flat:
+                               foreach($resultRows as $row)    {
+                                       $content.= $this->printResultRow($row);
+                               }
+                       break;
+               }
+               return '<div'.$this->pi_classParam('res').'>'.$content.'</div>';
+       }
 
 
 
@@ -381,96 +665,61 @@ class tx_indexedsearch extends tslib_pibase {
 
 
 
-       /**
-        * This splits the search word input into an array where each word is
-        *
-        * Only words with 2 or more characters are accepted
-        * Max 200 chars total
-        * Space is used to split words, "" can be used search for a whole string (not indexed search then)
-        * AND, OR and NOT are prefix words, overruling the default operator
-        * +/|/- equals AND, OR and NOT as operators.
-        * All search words are converted to lowercase.
-        *
-        * $defOp is the default operator. 1=OR, 0=AND
-        */
-       function getSearchWords($defOp) {
-               $inSW = substr($this->piVars["sword"],0,200);
 
-                       // Convert to UTF-8:
-               $inSW = $GLOBALS['TSFE']->csConvObj->utf8_encode($inSW, $GLOBALS['TSFE']->metaCharset);
 
-               if ($this->piVars["type"]==20)  {
-                       return array(array("sword"=>trim($inSW),"oper"=>"AND"));
-               } else {
-                       $search = t3lib_div::makeInstance("tslib_search");
-                       $search->default_operator = $defOp==1 ? 'OR' : 'AND';
-                       $search->operator_translate_table = $this->operator_translate_table;
-                       $search->register_and_explode_search_string($inSW);
 
-                       if (is_array($search->sword_array))     {
-                               return $search->sword_array;
-                       }
-               }
-       }
+
+       /***********************************
+        *
+        *      Searching functions (SQL)
+        *
+        ***********************************/
 
        /**
         * Returns a COMPLETE list of phash-integers matching the search-result composed of the search-words in the sWArr array.
         * The list of phash integers are unsorted and should be used for subsequent selection of index_phash records for display of the result.
+        *
+        * @param       array           Search word array
+        * @return      string          List of integers
         */
        function getPhashList($sWArr)   {
-               $c=0;
-
-               $totalHashList=array(); // This array accumulates the phash-values
-               $this->wSelClauses=array();
-
-               reset($sWArr);
-               while(list($k,$v)=each($sWArr)) {
-                       $sWord = strtolower($v["sword"]);       // lower-case all of them...
 
-                       $GLOBALS["TT"]->push("SearchWord ".$sWord);
+                       // Initialize variables:
+               $c=0;
+               $totalHashList = array();       // This array accumulates the phash-values
+               $this->wSelClauses = array();
 
-                       $plusQ="";
-/*
-                               // Maybe this will improve the search queries. Tests has shown it not to do so though...
-                       if (count($totalHashList))      {
-                               switch($v["oper"])      {
-                                       case "OR":
-                                               $plusQ = "AND IR.phash NOT IN (".implode(",",$totalHashList).")";
-                                       break;
-                                       case "AND NOT":
-                                       default:        // AND
-                                               $plusQ = "AND IR.phash IN (".implode(",",$totalHashList).")";
-                                       break;
-                               }
-                       }
-                       $plusQ="";
-*/
+                       // 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);
 
                                // Making the query for a single search word based on the search-type
-                       $res="";
-                       $theType = (string)$this->piVars["type"];
-                       if (strstr($sWord," ")) $theType=20;    // If there are spaces in the search-word, make a full text search instead.
+                       $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.
+                       $res = '';
+                       $wSel='';
 
-                       $wSel="";
+                               // Perform search for word:
                        switch($theType)        {
-                               case "1":
+                               case '1':
                                        $wSel = "IW.baseword LIKE '%".$GLOBALS['TYPO3_DB']->quoteStr($sWord, 'index_words')."%'";
-                                       $res = $this->execPHashListQuery($wSel,$plusQ);
-
+                                       $res = $this->execPHashListQuery($wSel,' AND is_stopword=0');
                                break;
-                               case "2":
+                               case '2':
                                        $wSel = "IW.baseword LIKE '".$GLOBALS['TYPO3_DB']->quoteStr($sWord, 'index_words')."%'";
-                                       $res = $this->execPHashListQuery($wSel,$plusQ);
+                                       $res = $this->execPHashListQuery($wSel,' AND is_stopword=0');
                                break;
-                               case "3":
+                               case '3':
                                        $wSel = "IW.baseword LIKE '%".$GLOBALS['TYPO3_DB']->quoteStr($sWord, 'index_words')."'";
-                                       $res = $this->execPHashListQuery($wSel,$plusQ);
+                                       $res = $this->execPHashListQuery($wSel,' AND is_stopword=0');
                                break;
-                               case "10":
-                                       $wSel = "IW.metaphone = ".$this->indexerObj->metaphone($sWord);
-                                       $res = $this->execPHashListQuery($wSel,$plusQ);
+                               case '10':
+                                       $wSel = 'IW.metaphone = '.$this->indexerObj->metaphone($sWord);
+                                       $res = $this->execPHashListQuery($wSel,' AND is_stopword=0');
                                break;
-                               case "20":
+                               case '20':
                                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
                                                                'ISEC.phash',
                                                                'index_section ISEC, index_fulltext IFT',
@@ -479,58 +728,62 @@ class tx_indexedsearch extends tslib_pibase {
                                                                        '.$this->sectionTableWhere(),
                                                                'ISEC.phash'
                                                        );
-                                       $wSel = "1=1";
+                                       $wSel = '1=1';
 
-                                       if ($this->piVars["type"]==20)  $this->piVars["order"]="mtime";         // If there is a fulltext search for a sentence there is a likelyness 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.
+                                       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:
-                                       $wSel = "IW.wid = ".$hash = $this->indexerObj->md5inthash($sWord);
-                                       $res = $this->execPHashListQuery($wSel,$plusQ);
+                                       $wSel = 'IW.wid = '.$hash = $this->indexerObj->md5inthash($sWord);
+                                       $res = $this->execPHashListQuery($wSel,' AND is_stopword=0');
                                break;
                        }
-                       $this->wSelClauses[]=$wSel;
+
+                               // Accumulate the word-select clauses
+                       $this->wSelClauses[] = $wSel;
 
                                // If there was a query to do, then select all phash-integers which resulted from this.
                        if ($res)       {
 
-                               # Get phash list by searching for it:
+                                       // Get phash list by searching for it:
                                $phashList = array();
                                while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))       {
-                                       $phashList[]=$row["phash"];
+                                       $phashList[] = $row['phash'];
                                }
                                $GLOBALS['TYPO3_DB']->sql_free_result($res);
 
                                        // Here the phash list are merged with the existing result based on whether we are dealing with OR, NOT or AND operations.
                                if ($c) {
-                                       switch($v["oper"])      {
-                                               case "OR":
-                                                       $totalHashList=array_unique(array_merge($phashList,$totalHashList));
+                                       switch($v['oper'])      {
+                                               case 'OR':
+                                                       $totalHashList = array_unique(array_merge($phashList,$totalHashList));
                                                break;
-                                               case "AND NOT":
-                                                       $totalHashList=array_diff($totalHashList,$phashList);
+                                               case 'AND NOT':
+                                                       $totalHashList = array_diff($totalHashList,$phashList);
                                                break;
                                                default:        // AND...
-                                                       $totalHashList=array_intersect($totalHashList,$phashList);
+                                                       $totalHashList = array_intersect($totalHashList,$phashList);
                                                break;
                                        }
                                } else {
-                                       $totalHashList=$phashList;      // First search
+                                       $totalHashList = $phashList;    // First search
                                }
-#debug($totalHashList);
                        }
 
-                       $GLOBALS["TT"]->pull();
+                       $GLOBALS['TT']->pull();
                        $c++;
                }
 
-#debug($sWArr);
-               return implode(",",$totalHashList);
+               return implode(',',$totalHashList);
        }
 
        /**
         * Returns a query which selects the search-word from the word/rel tables.
+        *
+        * @param       string          WHERE clause selecting the word from phash
+        * @param       string          Additional AND clause in the end of the query.
+        * @return      pointer         SQL result pointer
         */
-       function execPHashListQuery($wordSel,$plusQ="") {
+       function execPHashListQuery($wordSel,$plusQ='') {
                return $GLOBALS['TYPO3_DB']->exec_SELECTquery(
                                        'IR.phash',
                                        'index_words IW,
@@ -547,97 +800,124 @@ class tx_indexedsearch extends tslib_pibase {
 
        /**
         * Returns AND statement for selection of section in database. (rootlevel 0-2 + page_id)
+        *
+        * @return      string          AND clause for selection of section in database.
         */
        function sectionTableWhere()    {
-#debug($this->piVars["sections"]);
-               $out = $this->wholeSiteIdList<0 ? "" : "AND ISEC.rl0 IN (".$this->wholeSiteIdList.")";
-               $list = implode(",",t3lib_div::intExplode(",",substr($this->piVars["sections"],4)));
-
-               if (substr($this->piVars["sections"],0,4)=="rl1_")      {
-                       $out.= "AND ISEC.rl1 IN (".$list.")";
-               } else if (substr($this->piVars["sections"],0,4)=="rl2_")       {
-                       $out.= "AND ISEC.rl2 IN (".$list.")";
-               } else {
-                       switch((string)$this->piVars["sections"])       {
-                               case "-1":              // "-1" => "Only this page",
-                                       $out.= " AND ISEC.page_id=".$GLOBALS["TSFE"]->id;
+               $out = $this->wholeSiteIdList<0 ? '' : 'AND ISEC.rl0 IN ('.$this->wholeSiteIdList.')';
+
+               $match = '';
+               if (substr($this->piVars['sections'],0,4)=='rl1_')      {
+                       $list = implode(',',t3lib_div::intExplode(',',substr($this->piVars['sections'],4)));
+                       $out.= 'AND ISEC.rl1 IN ('.$list.')';
+                       $match = TRUE;
+               } elseif (substr($this->piVars['sections'],0,4)=='rl2_')        {
+                       $list = implode(',',t3lib_div::intExplode(',',substr($this->piVars['sections'],4)));
+                       $out.= 'AND ISEC.rl2 IN ('.$list.')';
+                       $match = TRUE;
+               } elseif (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['addRootLineFields']))      {
+                               // Traversing user configured fields to see if any of those are used to limit search to a section:
+                       foreach($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['addRootLineFields'] as $fieldName => $rootLineLevel)  {
+                               if (substr($this->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.')';
+                                       $match = TRUE;
+                                       break;
+                               }
+                       }
+               }
+
+                       // If no match above, test the static types:
+               if (!$match)    {
+                       switch((string)$this->piVars['sections'])       {
+                               case '-1':              // '-1' => 'Only this page',
+                                       $out.= ' AND ISEC.page_id='.$GLOBALS['TSFE']->id;
                                break;
-                               case "-2":              // "-2" => "Top + level 1",
-                                       $out.= " AND ISEC.rl2=0";
+                               case '-2':              // '-2' => 'Top + level 1',
+                                       $out.= ' AND ISEC.rl2=0';
                                break;
-                               case "-3":              // "-3" => "Level 2 and out",
-                                       $out.= " AND ISEC.rl2>0";
+                               case '-3':              // '-3' => 'Level 2 and out',
+                                       $out.= ' AND ISEC.rl2>0';
                                break;
                        }
                }
+
                return $out;
        }
 
        /**
         * Returns AND statement for selection of media type
+        *
+        * @return      string          AND statement for selection of media type
         */
        function mediaTypeWhere()       {
-               switch($this->piVars["media"])  {
-                       case 0:         // "0" => "Kun TYPO3 sider",
-                               $out = "AND IP.item_type=0";
-                       break;
-                       case 1:         // "1" => "Kun HTML dokumenter",
-                               $out = "AND IP.item_type=1";
-                       break;
-                       case 2:         // "2" => "Kun PDF dokumenter",
-                               $out = "AND IP.item_type=2";
+
+               switch((string)$this->piVars['media'])  {
+                       case '0':               // '0' => 'Kun TYPO3 sider',
+                               $out = 'AND IP.item_type='.$GLOBALS['TYPO3_DB']->fullQuoteStr('0', 'index_phash');;
                        break;
-                       case 3:         // "3" => "Kun Word dokumenter",
-                               $out = "AND IP.item_type=3";
+                       case '-2':              // All external documents
+                               $out = 'AND IP.item_type!='.$GLOBALS['TYPO3_DB']->fullQuoteStr('0', 'index_phash');;
                        break;
-                       case -2:                // All external documents
-                               $out = "AND IP.item_type>0";
+                       case '-1':      // All content
+                               $out='';
                        break;
-                       case -1:
                        default:
-                               $out="";
+                               $out = 'AND IP.item_type='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->piVars['media'], 'index_phash');
                        break;
                }
+
                return $out;
        }
 
        /**
         * Returns AND statement for selection of langauge
+        *
+        * @return      string          AND statement for selection of langauge
         */
        function languageWhere()        {
-               if ($this->piVars["lang"]>=0)   {       // -1 is the same as ALL language.
-                       return "AND IP.sys_language_uid=".intval($this->piVars["lang"]);
+               if ($this->piVars['lang']>=0)   {       // -1 is the same as ALL language.
+                       return 'AND IP.sys_language_uid='.intval($this->piVars['lang']);
                }
        }
 
        /**
-        * Execute final query:
+        * 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.
+        * @return      pointer         Query result pointer
         */
        function execFinalQuery($list)  {
 
-               $page_join="";
-               $page_where="";
-               if ($this->join_pages)  {
-                       $page_join = ",
-                               pages";
-                       $page_where = "pages.uid = ISEC.page_id
-                               ".$this->cObj->enableFields("pages")."
+                       // Setting up methods of filtering results based on page types, access, etc.
+               $page_join = '';
+               $page_where = '';
+
+                       // Calling hook for alternative creation of page ID list
+               if ($hookObj = &$this->hookRequest('execFinalQuery_idList'))    {
+                       $page_where = $hookObj->execFinalQuery_idList($list);
+               } elseif ($this->join_pages)    {       // Alternative to getting all page ids by ->getTreeList() where "excludeSubpages" is NOT respected.
+                       $page_join = ',
+                               pages';
+                       $page_where = 'pages.uid = ISEC.page_id
+                               '.$this->cObj->enableFields('pages').'
                                AND pages.no_search=0
                                AND pages.doktype<200
-                       ";
-               } elseif ($this->wholeSiteIdList>=0) {
-                       $siteIdNumbers = t3lib_div::intExplode(",",$this->wholeSiteIdList);
+                       ';
+               } elseif ($this->wholeSiteIdList>=0) {  // Collecting all pages IDs in which to search; filtering out ALL pages that are not accessible due to enableFields. Does NOT look for "no_search" field!
+                       $siteIdNumbers = t3lib_div::intExplode(',',$this->wholeSiteIdList);
                        $id_list=array();
                        while(list(,$rootId)=each($siteIdNumbers))      {
-                               $id_list[]=$this->cObj->getTreeList($rootId,9999,0,0,"","").$rootId;
+                               $id_list[] = $this->cObj->getTreeList($rootId,9999,0,0,'','').$rootId;
                        }
-                       $page_where = "ISEC.page_id IN (".implode(",",$id_list).")";
-               } else {
-                       $page_where = " 1=1 ";
+                       $page_where = 'ISEC.page_id IN ('.implode(',',$id_list).')';
+               } else {        // Disable everything... (select all)
+                       $page_where = ' 1=1 ';
                }
 
+
                        // If any of the ranking sortings are selected, we must make a join with the word/rel-table again, because we need to calculate ranking based on all search-words found.
-               if (substr($this->piVars["order"],0,5)=="rank_")        {
+               if (substr($this->piVars['order'],0,5)=='rank_')        {
                                /*
                                         OK there were some fancy calculations promoted by Graeme Merrall:
 
@@ -664,26 +944,26 @@ class tx_indexedsearch extends tslib_pibase {
 
                                        However I chose not to go with this for several reasons.
                                        I do not claim that my ways of calculating importance here is the best.
-                                       ANY (better) suggestions for ranking calculation is accepted! (as long as they are shipped with tested code in exchange for this.)
+                                       ANY (better) suggestion for ranking calculation is accepted! (as long as they are shipped with tested code in exchange for this.)
                                */
 
-                       switch($this->piVars["order"])  {
-                               case "rank_flag":       // This gives priority to word-position (max-value) so that words in title, keywords, description counts more than in content.
+                       switch($this->piVars['order'])  {
+                               case 'rank_flag':       // This gives priority to word-position (max-value) so that words in title, keywords, description counts more than in content.
                                                                        // The ordering is refined with the frequency sum as well.
-                                       $grsel = "MAX(IR.flags) AS order_val1, SUM(IR.freq) AS order_val2";
-                                       $orderBy = "order_val1".$this->isDescending().",order_val2".$this->isDescending();
+                                       $grsel = 'MAX(IR.flags) AS order_val1, SUM(IR.freq) AS order_val2';
+                                       $orderBy = 'order_val1'.$this->isDescending().',order_val2'.$this->isDescending();
                                break;
-                               case "rank_first":      // Results in average position of search words on page. Must be inversely sorted (low numbers are closer to top)
-                                       $grsel = "AVG(IR.first) AS order_val";
-                                       $orderBy = "order_val".$this->isDescending(1);
+                               case 'rank_first':      // Results in average position of search words on page. Must be inversely sorted (low numbers are closer to top)
+                                       $grsel = 'AVG(IR.first) AS order_val';
+                                       $orderBy = 'order_val'.$this->isDescending(1);
                                break;
-                               case "rank_count":      // Number of words found
-                                       $grsel = "SUM(IR.count) AS order_val";
-                                       $orderBy = "order_val".$this->isDescending();
+                               case 'rank_count':      // Number of words found
+                                       $grsel = 'SUM(IR.count) AS order_val';
+                                       $orderBy = 'order_val'.$this->isDescending();
                                break;
                                default:        // Frequency sum. I'm not sure if this is the best way to do it (make a sum...). Or should it be the average?
-                                       $grsel = "SUM(IR.freq) AS order_val";
-                                       $orderBy = "order_val".$this->isDescending();
+                                       $grsel = 'SUM(IR.freq) AS order_val';
+                                       $orderBy = 'order_val'.$this->isDescending();
                                break;
                        }
 
@@ -691,7 +971,7 @@ class tx_indexedsearch extends tslib_pibase {
                        $wordSel='('.implode(' OR ',$this->wSelClauses).') AND ';
 
                        return $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-                                               'ISEC.*, 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, '
+                                               'ISEC.*, IP.*, '
                                                .$grsel,
                                                'index_words IW,
                                                        index_rel IR,
@@ -712,21 +992,15 @@ class tx_indexedsearch extends tslib_pibase {
                } else {        // Otherwise, if sorting are done with the pages table or other fields, there is no need for joining with the rel/word tables:
 
                        $orderBy = '';
-                       switch((string)$this->piVars["order"])  {
-                               case "rating":
-                                       debug("rating: NOT ACTIVE YET");
-                               break;
-                               case "hits":
-                                       debug("rating: NOT ACTIVE YET");
-                               break;
-                               case "title":
-                                       $orderBy = "IP.item_title".$this->isDescending();
+                       switch((string)$this->piVars['order'])  {
+                               case 'title':
+                                       $orderBy = 'IP.item_title'.$this->isDescending();
                                break;
-                               case "crdate":
-                                       $orderBy = "IP.item_crdate".$this->isDescending();
+                               case 'crdate':
+                                       $orderBy = 'IP.item_crdate'.$this->isDescending();
                                break;
-                               case "mtime":
-                                       $orderBy = "IP.item_mtime".$this->isDescending();
+                               case 'mtime':
+                                       $orderBy = 'IP.item_mtime'.$this->isDescending();
                                break;
                        }
 
@@ -745,51 +1019,72 @@ class tx_indexedsearch extends tslib_pibase {
        }
 
        /**
-        * Checking if the resume can be shown for the search result:
+        * Checking if the resume can be shown for the search result (depending on whether the rights are OK)
+        * ? Should it also check for gr_list "0,-1"?
+        *
+        * @param       array           Result row array.
+        * @return      boolean         Returns true if resume can safely be shown
         */
        function checkResume($row)      {
-               if ($row["item_type"]>0)        {
-                               // phash_t3 is the phash of the parent TYPO3 page row which initiated the indexing of the documents in this section.
 
-                               // So, selecting for the grlist records belonging to the parent phash-row where the current users gr_list exists.
-                               // If this is NOT found, there is still a theoretical possibility that another user accessible page would display a link, so maybe the resume of such a document here may be unjustified hidden. But this case is rare.
+                       // If the record is indexed by an indexing configuration, just show it.
+                       // At least this is needed for external URLs and files.
+                       // For records we might need to extend this - for instance block display if record is access restricted.
+               if ($row['freeIndexUid'])       {
+                       return TRUE;
+               }
+
+                       // Evaluate regularly indexed pages based on item_type:
+               if ($row['item_type'])  {       // External media:
+                               // For external media we will check the access of the parent page on which the media was linked from.
+                               // "phash_t3" is the phash of the parent TYPO3 page row which initiated the indexing of the documents in this section.
+                               // So, selecting for the grlist records belonging to the parent phash-row where the current users gr_list exists will help us to know.
+                               // If this is NOT found, there is still a theoretical possibility that another user accessible page would display a link, so maybe the resume of such a document here may be unjustified hidden. But better safe than sorry.
                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('phash', 'index_grlist', 'phash='.intval($row['phash_t3']).' AND gr_list='.$GLOBALS['TYPO3_DB']->fullQuoteStr($GLOBALS['TSFE']->gr_list, 'index_grlist'));
                        if ($GLOBALS['TYPO3_DB']->sql_num_rows($res))   {
-#                              debug("Look up for external media '".$row["data_filename"]."': phash:".$row["phash_t3"]." YES - (".$GLOBALS["TSFE"]->gr_list.")!",1);
-                               return 1;
+                               #debug("Look up for external media '".$row['data_filename']."': phash:".$row['phash_t3'].' YES - ('.$GLOBALS['TSFE']->gr_list.")!",1);
+                               return TRUE;
                        } else {
-#                              debug("Look up for external media '".$row["data_filename"]."': phash:".$row["phash_t3"]." NO - (".$GLOBALS["TSFE"]->gr_list.")!",1);
-                               return 0;
+                               #debug("Look up for external media '".$row['data_filename']."': phash:".$row['phash_t3'].' NO - ('.$GLOBALS['TSFE']->gr_list.")!",1);
+                               return FALSE;
                        }
-               } else {        // ALm typo3 pages:
-                       if (strcmp($row["gr_list"],$GLOBALS["TSFE"]->gr_list))  {
+               } else {        // Ordinary TYPO3 pages:
+                       if (strcmp($row['gr_list'],$GLOBALS['TSFE']->gr_list))  {
                                        // Selecting for the grlist records belonging to the phash-row where the current users gr_list exists. If it is found it is proof that this user has direct access to the phash-rows content although he did not himself initiate the indexing...
                                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('phash', 'index_grlist', 'phash='.intval($row['phash']).' AND gr_list='.$GLOBALS['TYPO3_DB']->fullQuoteStr($GLOBALS['TSFE']->gr_list, 'index_grlist'));
                                if ($GLOBALS['TYPO3_DB']->sql_num_rows($res))   {
-                                       #debug("Checking on it ...".$row["item_title"]."/".$row["phash"]." - YES (".$GLOBALS["TSFE"]->gr_list.")",1);
-                                       return 1;
+                                       #debug('Checking on it ...'.$row['item_title'].'/'.$row['phash'].' - YES ('.$GLOBALS['TSFE']->gr_list.")",1);
+                                       return TRUE;
                                } else {
-                                       #debug("Checking on it ...".$row["item_title"]."/".$row["phash"]." - NOPE",1);
-                                       return 0;
+                                       #debug('Checking on it ...'.$row['item_title'].'/'.$row['phash']." - NOPE",1);
+                                       return FALSE;
                                }
                        } else {
-                                       #debug("Resume can be shown, because the document was in fact indexed by this combination of groups!".$GLOBALS["TSFE"]->gr_list." - ".$row["item_title"]."/".$row["phash"],1);
-                               return 1;
+                                       #debug('Resume can be shown, because the document was in fact indexed by this combination of groups!'.$GLOBALS['TSFE']->gr_list.' - '.$row['item_title'].'/'.$row['phash'],1);
+                               return TRUE;
                        }
                }
        }
 
        /**
-        * Returns "DESC" or "" depending on the settings of the incoming highest/lowest result order.
+        * Returns "DESC" or "" depending on the settings of the incoming highest/lowest result order (piVars['desc']
+        *
+        * @param       boolean         If true, inverse the order which is defined by piVars['desc']
+        * @return      string          " DESC" or ""
         */
-       function isDescending($inverse=0)       {
-               $desc = $this->piVars["desc"];
+       function isDescending($inverse=FALSE)   {
+               $desc = $this->piVars['desc'];
                if ($inverse)   $desc=!$desc;
-               return !$desc ? " DESC":"";
+               return !$desc ? ' DESC':'';
        }
 
        /**
-        * Write statistics information for the search:
+        * Write statistics information to database for the search operation
+        *
+        * @param       array           Search Word array
+        * @param       integer         Number of hits
+        * @param       integer         Milliseconds the search took
+        * @return      void
         */
        function writeSearchStat($sWArr,$count,$pt)     {
                $insertFields = array(
@@ -808,7 +1103,7 @@ class tx_indexedsearch extends tslib_pibase {
                if ($newId)     {
                        foreach($sWArr as $val) {
                                $insertFields = array(
-                                       'word' => strtolower($val['sword']),
+                                       'word' => $GLOBALS['TSFE']->csConvObj->conv_case('utf-8', $val['sword'], 'toLower'),
                                        'index_stat_search_id' => $newId,
                                        'tstamp' => $GLOBALS['EXEC_TIME']               // Time stamp
                                );
@@ -831,197 +1126,256 @@ class tx_indexedsearch extends tslib_pibase {
 
 
        /***********************************
-
-               LAYOUT FUNCTIONS
-
-       ***********************************/
-
-
-
+        *
+        * HTML output functions
+        *
+        ***********************************/
 
        /**
-        * Make search form
+        * Make search form HTML
+        *
+        * @param       array           Value/Labels pairs for search form selector boxes.
+        * @return      string          Search form HTML
         */
        function makeSearchForm($optValues)     {
-               $rows=array();
+
+                       // Accumulate table rows here:
+               $rows = array();
+
                        // Adding search field and button:
                $rows[]='<tr>
-                               <td nowrap><p>'.$this->pi_getLL("form_searchFor").'&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").'"'.$this->pi_classParam("searchbox-button").'></td>
+                               <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>';
 
-               if ($this->conf["show."]["clearSearchBox"] && $this->conf["show."]["clearSearchBox."]['enableSubSearchCheckBox'])       {
+               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"':'').'> Add to current search words</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>';
                }
 
-
-               if ($this->piVars["ext"])       {
-                       if (is_array($optValues["type"]) || is_array($optValues["defOp"]))      $rows[]='<tr>
-                                       <td nowrap><p>'.$this->pi_getLL("form_match").'&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>
+                       // Extended search options:
+               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><p>'.$this->pi_getLL("form_searchIn").'&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>
+                       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><p>'.$this->pi_getLL("form_fromSection").'&nbsp;</p></td>
-                                       <td>'.$this->renderSelectBox($this->prefixId.'[sections]',$this->piVars["sections"],$optValues["sections"]).'</td>
+                       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><p>'.$this->pi_getLL("form_orderBy").'&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").'</p></td>
+                       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><p>'.$this->pi_getLL("form_style").'&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":"").'>'.$this->pi_getLL("form_extResume"):'').'</p></td>
+                       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>';
                }
 
-#debug(array($GLOBALS["TSFE"]->id,$GLOBALS["TSFE"]->sPre,$this->pi_getPageLink($GLOBALS["TSFE"]->id,$GLOBALS["TSFE"]->sPre)));
-
-               $out='<table '.$this->conf["tableParams."]["searchBox"].'>
-                                       <form action="'.$this->pi_getPageLink($GLOBALS["TSFE"]->id,$GLOBALS["TSFE"]->sPre).'" method="POST" name="'.$this->prefixId.'">
+                       // 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).'
-                                               <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>
-                               </table>';
+                               </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="'.$this->pi_getPageLink($GLOBALS["TSFE"]->id,$GLOBALS["TSFE"]->sPre,array($this->prefixId."[ext]"=>0)).'">'.$this->pi_getLL("link_regularSearch").'</a>' :
-                                       '<a href="'.$this->pi_getPageLink($GLOBALS["TSFE"]->id,$GLOBALS["TSFE"]->sPre,array($this->prefixId."[ext]"=>1)).'">'.$this->pi_getLL("link_advancedSearch").'</a>'
+                               ($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>';
+               return '<div'.$this->pi_classParam('searchbox').'>'.$out.'</div>';
        }
 
        /**
         * Print the searching rules
+        *
+        * @return      string          Rules for the search
         */
        function printRules()   {
-               $out = "";
-               if ($this->conf["show."]["rules"])      {
-                       $out = '<h2>'.$this->pi_getLL("rules_header").'</h2><p>'.nl2br(htmlspecialchars(trim($this->pi_getLL("rules_text")))).'</p>';
-                       $out = '<div'.$this->pi_classParam("rules").'>'.$this->cObj->stdWrap($out, $this->conf["rules_stdWrap."]).'</div>';
+               $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>';
                }
                return $out;
        }
 
        /**
         * Returns the anchor-links to the sections inside the displayed result rows.
+        *
+        * @return      string
         */
        function printResultSectionLinks()      {
-               $lines=array();
-               reset($this->resultSections);
-               while(list($id,$dat)=each($this->resultSections))       {
-                       $lines[]='<li><a href="'.$this->anchorPrefix.'#'.md5($id).'">'.(trim($dat[0])?htmlspecialchars(trim($dat[0])):$this->pi_getLL("unnamedSection")).' ('.$dat[1].' '.$this->pi_getLL("word_page".($dat[1]>1?"s":"")).')</a></li>';
-               }
-               $out = '<ul>'.implode(chr(10),$lines).'</ul>';
-               return '<div'.$this->pi_classParam("sectionlinks").'>'.$this->cObj->stdWrap($out, $this->conf["sectionlinks_stdWrap."]).'</div>';
-       }
-
-       /**
-        * Returns the links for the result browser bar (next/prev/1-2-3)
-        */
-       function makePointerSelector($count,$displayCount,$pointer)     {
-               $lines=array();
-
-                       // Previous pointer:
-               if ($pointer>0) {
-                       $lines[]=$this->makePointerSelector_link("PREV",0);
-               }
+               if (count($this->resultSections))       {
+                       $lines = array();
 
-                       // 1-2-3
-               for ($a=0;$a<t3lib_div::intInRange(ceil($count/$displayCount),1,10);$a++)       {
-#                      $str = ($a*$displayCount+1)."-".(($a+1)*$displayCount);
-                       $str = $a+1;
-                       $linkStr = $this->makePointerSelector_link($str,$a);
-                       $lines[]=       $pointer==$a ? '<strong>['.$linkStr.']</strong>' : $linkStr;
+                       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>';
+                       }
+                       $out = '<ul>'.implode(chr(10),$lines).'</ul>';
+                       return '<div'.$this->pi_classParam('sectionlinks').'>'.$this->cObj->stdWrap($out, $this->conf['sectionlinks_stdWrap.']).'</div>';
                }
-
-                       // Next pointer:
-               if ($pointer+1<ceil($count/$displayCount))      $lines[]=$this->makePointerSelector_link("NEXT",$pointer+1);
-
-               return implode(" - ",$lines);
        }
 
        /**
-        * Used to make the link for the result-browser.
-        * Notive now the links must resubmit the form after setting the new pointer-value in a hidden formfield.
+        * Returns the section header of the search result.
+        *
+        * @param       string          ID for the section (used for anchor link)
+        * @param       string          Section title with linked wrapped around
+        * @param       integer         Number of results in section
+        * @return      string          HTML output
         */
-       function makePointerSelector_link($str,$p)      {
-               return '<a href="#" onClick="document.'.$this->prefixId.'[\''.$this->prefixId.'[pointer]\'].value=\''.$p.'\';document.'.$this->prefixId.'.submit();return false;">'.$str.'</a>';
+       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>';
        }
 
        /**
-        * Returns a string that tells which search words are searched for.
+        * This prints a single result row, including a recursive call for subrows.
+        *
+        * @param       array           Search result row
+        * @param       integer         1=Display only header (for sub-rows!), 2=nothing at all
+        * @return      string          HTML code
         */
-       function tellUsWhatIsSeachedFor($sWArr) {
-               reset($sWArr);
-               $searchingFor="";
-               $c=0;
-               while(list($k,$v)=each($sWArr)) {
-                       if ($c) {
-                               switch($v["oper"])      {
-                                       case "OR":
-                                               $searchingFor.=" ".$this->pi_getLL("searchFor_or")." ".$this->wrapSW($v["sword"]);
-                                       break;
-                                       case "AND NOT":
-                                               $searchingFor.=" ".$this->pi_getLL("searchFor_butNot")." ".$this->wrapSW($v["sword"]);
-                                       break;
-                                       default:        // AND...
-                                               $searchingFor.=" ".$this->pi_getLL("searchFor_and")." ".$this->wrapSW($v["sword"]);
-                                       break;
-                               }
+       function printResultRow($row, $headerOnly=0)    {
 
-                       } else {
-                               $searchingFor=$this->pi_getLL("searchFor")." ".$this->utf8_to_currentCharset($this->wrapSW($v["sword"]));
+                       // Get template content:
+               $tmplContent = $this->prepareResultRowTemplateData($row, $headerOnly);
+
+               if ($hookObj = &$this->hookRequest('printResultRow'))   {
+                       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
+                       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>';
+                       } elseif ($headerOnly==1) {
+                               $out.='<tr>
+                                       <td></td>
+                                       <td colspan="2"'.$this->pi_classParam('descr'.$tmplContent['CSSsuffix']).'><p>'.$tmplContent['description'].'</p></td>
+                               </tr>';
                        }
-                       $c++;
-               }
-               return $searchingFor;
-       }
 
-       /**
-        * Wraps the search words in the search-word list display (from ->tellUsWhatIsSeachedFor())
-        */
-       function wrapSW($str)   {
-               return "'<span".$this->pi_classParam("sw").">".htmlspecialchars($str)."</span>'";
-       }
+                               // 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>';
 
-       /**
-        * Makes a selector box
-        */
-       function renderSelectBox($name,$value,$optValues)       {
-               if (is_array($optValues))       {
-                       $opt=array();
-                       $isSelFlag=0;
-                       reset($optValues);
-                       while(list($k,$v)=each($optValues))     {
-                               $sel = (!strcmp($k,$value)?" SELECTED":"");
-                               if ($sel)       $isSelFlag++;
-                               $opt[]='<option value="'.htmlspecialchars($k).'"'.$sel.'>'.htmlspecialchars($v).'</option>';
+                                       foreach($row['_sub'] as $subRow)        {
+                                               $out.='<tr>
+                                                       <td></td>
+                                                       <td colspan="2"><p>'.$this->printResultRow($subRow,1).'</p></td>
+                                               </tr>';
+                                       }
+                               } else {
+                                       $out.='<tr>
+                                               <td></td>
+                                               <td colspan="2"><p>'.$this->pi_getLL('res_otherPageAsWell','',1).'</p></td>
+                                       </tr>';
+                               }
                        }
-       #               if (!$isSelFlag && strcmp("",$value))   $opt[]='<option value="'.$value.'" SELECTED>'.htmlspecialchars("CURRENT VALUE '".$value."' DID NOT EXIST AMONG THE OPTIONS").'</option>';
-                       return '<select name="'.$name.'">'.implode("",$opt).'</select>';
+
+                       return '<table '.$this->conf['tableParams.']['searchRes'].'>'.$out.'</table><br/>';
                }
        }
 
+       /**
+        * Returns a results browser
+        *
+        * @param       boolean         Show result count
+        * @param       string          String appended to "displaying results..." notice.
+        * @param       string          String appended after section "displaying results..."
+        * @return      string          HTML output
+        */
+       function pi_list_browseresults($showResultCount=1,$addString='',$addPart='')    {
 
+                       // 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();
 
+                       // 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>';
+               }
 
+               $pR1 = $pointer*$results_at_a_time+1;
+               $pR2 = $pointer*$results_at_a_time+$results_at_a_time;
+               $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>')),
+                               $pR1,
+                               min(array($this->internal['res_count'],$pR2)),
+                               $this->internal['res_count']
+                               ).$addString.'</p>':''
+                       ).$addPart.
+               '<table>
+                       <tr>'.implode('',$links).'</tr>
+               </table></div>';
 
+               return $sTables;
+       }
 
 
 
@@ -1032,393 +1386,418 @@ class tx_indexedsearch extends tslib_pibase {
 
 
 
-       /***********************************
 
-               Result row LAYOUT
 
-       ***********************************/
+       /***********************************
+        *
+        * Support functions for HTML output (with a minimum of fixed markup)
+        *
+        ***********************************/
 
        /**
-        * Takes the array with resultrows as input and returns the result-HTML-code
-        * Takes the "group" var into account: Makes a "section" or "flat" display.
+        * Preparing template data for the result row output
+        *
+        * @param       array           Result row
+        * @param       boolean         If set, display only header of result (for sub-results)
+        * @return      array           Array with data to insert in result row template
         */
-       function compileResult($resultRows)     {
-               $content="";
+       function prepareResultRowTemplateData($row, $headerOnly)        {
 
-               $newResultRows=array();
-               reset($resultRows);
-               while(list(,$row)=each($resultRows))    {
-                       $id = md5($row["phash_grouping"]);
-                       if (is_array($newResultRows[$id]))      {
-                               if (!$newResultRows[$id]["show_resume"] && $row["show_resume"]) {       // swapping:
-                                               // Remove old
-                                       $subrows = $newResultRows[$id]["_sub"];
-                                       unset($newResultRows[$id]["_sub"]);
-                                       $subrows[] =$newResultRows[$id];
+                       // Initialize:
+               $specRowConf = $this->getSpecialConfigForRow($row);
+               $CSSsuffix = $specRowConf['CSSsuffix']?'-'.$specRowConf['CSSsuffix']:'';
 
-                                               // Insert new:
-                                       $newResultRows[$id]=$row;
-                                       $newResultRows[$id]["_sub"]=$subrows;
-                               } else $newResultRows[$id]["_sub"][]=$row;
-                       } else {
-                               $newResultRows[$id]=$row;
+                       // If external media, link to the media-file instead.
+               if ($row['item_type'])  {               // External media
+                       if ($row['show_resume'])        {       // Can link directly.
+                               $title = '<a href="'.htmlspecialchars($row['data_filename']).'">'.htmlspecialchars($this->makeTitle($row)).'</a>';
+                       } else {        // Suspicious, so linking to page instead...
+                               $copy_row = $row;
+                               unset($copy_row['cHashParams']);
+                               $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);
                }
-               $resultRows=$newResultRows;
 
+               $tmplContent = array();
+               $tmplContent['title'] = $title;
+               $tmplContent['result_number'] = $row['result_number'];
+               $tmplContent['icon'] = $this->makeItemTypeIcon($row['item_type'],'',$specRowConf);
+               $tmplContent['rating'] = $this->makeRating($row);
+               $tmplContent['description'] = $this->makeDescription($row,$this->piVars['extResume'] && !$headerOnly?0:1);
+               $tmplContent = $this->makeInfo($row,$tmplContent);
+               $tmplContent['access'] = $this->makeAccessIndication($row['page_id']);
+               $tmplContent['language'] = $this->makeLanguageIndication($row);
+               $tmplContent['CSSsuffix'] = $CSSsuffix;
+
+                       // Post processing with hook.
+               if ($hookObj = &$this->hookRequest('prepareResultRowTemplateData_postProc'))    {
+                       $tmplContent = $hookObj->prepareResultRowTemplateData_postProc($tmplContent, $row, $headerOnly);
+               }
 
-               switch($this->piVars["group"])  {
-                       case "sections":
-                               $rl2flag = substr($this->piVars["sections"],0,2)=="rl";
-                               $sections=array();
-                               reset($resultRows);
-                               while(list(,$row)=each($resultRows))    {
-                                       $id = $row["rl0"]."-".$row["rl1"].($rl2flag?"-".$row["rl2"]:"");
-                                       $sections[$id][]=$row;
-                               }
-
-                               $this->resultSections=array();
-                               reset($sections);
-                               while(list($id,$resultRows)=each($sections))    {
-                                       $rlParts = explode("-",$id);
+               return $tmplContent;
+       }
 
-                                       $theId = $rlParts[2]?$rlParts[2]:($rlParts[1]?$rlParts[1]:$rlParts[0]);
-                                       $theRLid = $rlParts[2]?"rl2_".$rlParts[2]:($rlParts[1]?"rl1_".$rlParts[1]:"0");
+       /**
+        * Returns a string that tells which search words are searched for.
+        *
+        * @param       array           Array of search words
+        * @return      string          HTML telling what is searched for.
+        */
+       function tellUsWhatIsSeachedFor($sWArr) {
 
-                                       $sectionName = substr($this->getPathFromPageId($theId),1);
-                                       if (!trim($sectionName))        {
-                                               $sectionTitleLinked=$this->pi_getLL("unnamedSection").":";
-                                       } else {
-                                               $sectionTitleLinked = '<a href="#" onClick="document.'.$this->prefixId.'[\''.$this->prefixId.'[_sections]\'].value=\''.$theRLid.'\';document.'.$this->prefixId.'.submit();return false;">'.$sectionName.':</a>';
-                                       }
+                       // Init:
+               $searchingFor = '';
+               $c=0;
 
-                                       $content.=$this->makeSectionHeader($id,$sectionTitleLinked,count($resultRows));
-                                       $this->resultSections[$id] = array($sectionName,count($resultRows));
-                                       reset($resultRows);
-                                       while(list(,$row)=each($resultRows))    {
-                                               $content.=$this->printResultRow($row);
-                                       }
-                               }
-                       break;
-                       default:        // flat:
-                               reset($resultRows);
-                               while(list(,$row)=each($resultRows))    {
-                                       $content.=$this->printResultRow($row);
+                       // Traverse search words:
+               foreach($sWArr as $k => $v)     {
+                       if ($c) {
+                               switch($v['oper'])      {
+                                       case 'OR':
+                                               $searchingFor.= ' '.$this->pi_getLL('searchFor_or','',1).' '.$this->wrapSW($this->utf8_to_currentCharset($v['sword']));
+                                       break;
+                                       case 'AND NOT':
+                                               $searchingFor.= ' '.$this->pi_getLL('searchFor_butNot','',1).' '.$this->wrapSW($this->utf8_to_currentCharset($v['sword']));
+                                       break;
+                                       default:        // AND...
+                                               $searchingFor.= ' '.$this->pi_getLL('searchFor_and','',1).' '.$this->wrapSW($this->utf8_to_currentCharset($v['sword']));
+                                       break;
                                }
-                       break;
+                       } else {
+                               $searchingFor = $this->pi_getLL('searchFor','',1).' '.$this->wrapSW($this->utf8_to_currentCharset($v['sword']));
+                       }
+                       $c++;
                }
-               return '<div'.$this->pi_classParam("res").'>'.$content.'</div>';
+               return $searchingFor;
        }
 
        /**
-        * Returns the section header of the search result.
+        * Wraps the search words in the search-word list display (from ->tellUsWhatIsSeachedFor())
+        *
+        * @param       string          search word to wrap (in local charset!)
+        * @return      string          Search word wrapped in <span> tag.
         */
-       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><p>'.$countResultRows.' '.$this->pi_getLL("word_page".($countResultRows>1?"s":"")).'</p></td>
-                                               </tr>
-                                       </table></div>';
+       function wrapSW($str)   {
+               return '"<span'.$this->pi_classParam('sw').'>'.htmlspecialchars($str).'</span>"';
        }
 
        /**
-        * This prints a single result row, including a recursive call for subrows.
+        * Makes a selector box
+        *
+        * @param       string          Name of selector box
+        * @param       string          Current value
+        * @param       array           Array of options in the selector box (value => label pairs)
+        * @return      string          HTML of selector box
         */
-       function printResultRow($row,$headerOnly=0)     {
-               $specRowConf = $this->getSpecialConfigForRow($row);
-               $CSSsuffix = $specRowConf["CSSsuffix"]?"-".$specRowConf["CSSsuffix"]:"";
+       function renderSelectBox($name,$value,$optValues)       {
+               if (is_array($optValues))       {
+                       $opt = array();
+                       $isSelFlag = 0;
 
-                       // If external media, link to the media-file instead.
-               if ($row["item_type"])  {
-                       if ($row["show_resume"])        {       // Can link directly.
-                               $title = '<a href="'.$row["data_filename"].'">'.$row["result_number"].": ".$this->makeTitle($row).'</a>';
-                       } else {        // Suspicious, so linking to page instead...
-                               $copy_row=$row;
-                               unset($copy_row["cHashParams"]);
-                               $title = $this->linkPage($row["page_id"],$row["result_number"].": ".$this->makeTitle($row),$copy_row);
+                       foreach($optValues as $k => $v) {
+                               $sel = (!strcmp($k,$value) ? ' selected="selected"' : '');
+                               if ($sel)       $isSelFlag++;
+                               $opt[] = '<option value="'.htmlspecialchars($k).'"'.$sel.'>'.htmlspecialchars($v).'</option>';
                        }
-               } else {        // Else the page:
-                       $title = $this->linkPage($row["data_page_id"],$row["result_number"].": ".$this->makeTitle($row),$row);
-               }
-
-                       // Make the header row with title, icon and rating bar.:
-               $out.='<tr '.$this->pi_classParam("title".$CSSsuffix).'>
-                       <td width="16">'.$this->makeItemTypeIcon($row["item_type"],"",$specRowConf).'</td>
-                       <td width="95%" nowrap><p>'.$title.'</p></td>
-                       <td nowrap><p'.$this->pi_classParam("percent".$CSSsuffix).'>'.$this->makeRating($row).'</p></td>
-               </tr>';
-
-                       // Print the resume-section. If headerOnly is 1, then  only the short resume is printed
-               if (!$headerOnly)       {
-                       $out.='<tr>
-                               <td></td>
-                               <td colspan=2'.$this->pi_classParam("descr".$CSSsuffix).'><p>'.$this->makeDescription($row,$this->piVars["extResume"]?0:1).'</p></td>
-                       </tr>';
-                       $out.='<tr>
-                               <td></td>
-                               <td '.$this->pi_classParam("info".$CSSsuffix).' nowrap><p>'.$this->makeInfo($row).'</p></td>
-                               <td '.$this->pi_classParam("info".$CSSsuffix).' align="right"><p>'.$this->makeAccessIndication($row["page_id"]).''.$this->makeLanguageIndication($row).'</p></td>
-                       </tr>';
-               } elseif ($headerOnly==1) {
-                       $out.='<tr>
-                               <td></td>
-                               <td colspan=2'.$this->pi_classParam("descr".$CSSsuffix).'><p>'.$this->makeDescription($row,1,180).'</p></td>
-                       </tr>';
-               } elseif ($headerOnly==2) {
-                       // nothing.
-               }
-
-                       // 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 ($row["item_type"]==2)       {
-                               $out.='<tr>
-                                       <td></td>
-                                       <td colspan=2><p><BR>'.$this->pi_getLL("res_otherMatching").'<BR><BR></p></td>
-                               </tr>';
 
-                               reset($row["_sub"]);
-                               while(list(,$subRow)=each($row["_sub"]))        {
-                                       $out.='<tr>
-                                               <td></td>
-                                               <td colspan=2><p>'.$this->printResultRow($subRow,1).'</p></td>
-                                       </tr>';
-                               }
-                       } else {
-                               $out.='<tr>
-                                       <td></td>
-                                       <td colspan=2><p>'.$this->pi_getLL("res_otherPageAsWell").'</p></td>
-                               </tr>';
-                       }
+                       return '<select name="'.$name.'">'.implode('',$opt).'</select>';
                }
-
-               return '<table '.$this->conf["tableParams."]["searchRes"].'>'.$out.'</table><BR>';
        }
 
        /**
-        * Return the icon corresponding to media type $it;
+        * Used to make the link for the result-browser.
+        * Notice how the links must resubmit the form after setting the new pointer-value in a hidden formfield.
+        *
+        * @param       string          String to wrap in <a> tag
+        * @param       integer         Pointer value
+        * @return      string          Input string wrapped in <a> tag with onclick event attribute set.
         */
-       function makeItemTypeIcon($it,$alt="",$specRowConf=array())     {
-               $spec_flag = 0;
+       function makePointerSelector_link($str,$p)      {
+               $onclick = 'document.'.$this->prefixId.'[\''.$this->prefixId.'[pointer]\'].value=\''.$p.'\';document.'.$this->prefixId.'.submit();return false;';
+               return '<a href="#" onclick="'.htmlspecialchars($onclick).'">'.$str.'</a>';
+       }
 
-               switch($it)     {
-                       case 1:
-                               $icon="html.gif";
-                       break;
-                       case 2:
-                               $icon="pdf.gif";
-                       break;
-                       case 3:
-                               $icon="doc.gif";
-                       break;
-                       case 4:
-                               $icon="txt.gif";
-                       break;
-                       default:
-                               $icon="pages.gif";
-                               if (is_array($specRowConf["pageIcon."]))        {
-                                       $spec_flag = 1;
-                                       $spec = $this->cObj->IMAGE($specRowConf["pageIcon."]);
+       /**
+        * Return icon for file extension
+        *
+        * @param       string          File extension / item type
+        * @param       string          Title attribute value in icon.
+        * @param       array           TypoScript configuration specifically for search result.
+        * @return      string          <img> tag for icon
+        */
+       function makeItemTypeIcon($it,$alt='',$specRowConf)     {
+               if (!isset($this->iconFileNameCache[$it]))      {
+                       $this->iconFileNameCache[$it] = '';
+
+                               // If TypoScript is used to render the icon:
+                       if (is_array($this->conf['iconRendering.']))    {
+                               $this->cObj->setCurrentVal($it);
+                               $this->iconFileNameCache[$it] = $this->cObj->cObjGetSingle($this->conf['iconRendering'],$this->conf['iconRendering.']);
+                       } else { // ... otherwise, get flag from sys_language record:
+
+                                       // Default creation / finding of icon:
+                               $icon = '';
+                               if ($it==='0')  {
+                                       if (is_array($specRowConf['pageIcon.']))        {
+                                               $this->iconFileNameCache[$it] = $this->cObj->IMAGE($specRowConf['pageIcon.']);
+                                       } else {
+                                               $icon = 'EXT:indexed_search/pi/res/pages.gif';
+                                       }
+                               } elseif ($this->external_parsers[$it]) {
+                                       $icon = $this->external_parsers[$it]->getIcon($it);
                                }
-                       break;
-               }
-               if ($spec_flag) {
-                       return $spec;
-               } else {
-                       $fullPath = t3lib_extMgm::siteRelPath("indexed_search").'pi/res/'.$icon;
-                       $info = @getimagesize(PATH_site.$fullPath);
 
-                       return is_array($info) ? '<img src="'.$fullPath.'" hspace=3 '.$info[3].' title="'.htmlspecialchars($alt).'">' : '';
+                               if ($icon)      {
+                                       $fullPath = t3lib_div::getFileAbsFileName($icon);
+
+                                       if ($fullPath)  {
+                                               $info = @getimagesize($fullPath);
+                                               $iconPath = substr($fullPath,strlen(PATH_site));
+                                               $this->iconFileNameCache[$it] = is_array($info) ? '<img src="'.$iconPath.'" '.$info[3].' title="'.htmlspecialchars($alt).'" alt="" />' : '';
+                                       }
+                               }
+                       }
                }
+               return $this->iconFileNameCache[$it];
        }
 
        /**
         * Return the rating-HTML code for the result row. This makes use of the $this->firstRow
+        *
+        * @param       array           Result row array
+        * @return      string          String showing ranking value
         */
        function makeRating($row)       {
-/*
-                               "rank_flag" => "Rang, prioritet",
-                               "rank_freq" => "Rang, frekvens",
-                               "rank_first" => "Rang, tæt på toppen",
-                               "rank_count" => "Rang, antal forekomster",
-                               "rating" => "Side-rating",
-                               "hits" => "Side-hits",
-                               "title" => "Dokumenttitel",
-                               "crdate" => "Oprettelsesdato",
-                               "mtime" => "Ændringsdato",
-*/
-               switch((string)$this->piVars["order"])  {
-                       case "rank_count":
-                               return $row["order_val"]." matches";
+
+               switch((string)$this->piVars['order'])  {
+                       case 'rank_count':              // Number of occurencies on page
+                               return $row['order_val'].' '.$this->pi_getLL('maketitle_matches');
                        break;
-                       case "rank_first":
-                               return ceil(t3lib_div::intInRange(255-$row["order_val"],1,255)/255*100)."%";
+                       case 'rank_first':      // Close to top of page
+                               return ceil(t3lib_div::intInRange(255-$row['order_val'],1,255)/255*100).'%';
                        break;
-                       case "rank_flag":
-                               if ($this->firstRow["order_val2"])      {
-                                       $base=$row["order_val1"]*256; // (3 MSB bit, 224 is highest value of order_val1 currently)
-                                       $freqNumber = $row["order_val2"]/$this->firstRow["order_val2"]*pow(2,13);       // 16-3 MSB = 13
+                       case 'rank_flag':       // Based on priority assigned to <title> / <meta-keywords> / <meta-description> / <body>
+                               if ($this->firstRow['order_val2'])      {
+                                       $base = $row['order_val1']*256; // (3 MSB bit, 224 is highest value of order_val1 currently)
+                                       $freqNumber = $row['order_val2']/$this->firstRow['order_val2']*pow(2,13);       // 16-3 MSB = 13
                                        $total = t3lib_div::intInRange($base+$freqNumber,0,65536);
                                        #debug($total);
                                        #debug(log($total)/log(65536)*100,1);
-                                       return ceil(log($total)/log(65536)*100)."%";
+                                       return ceil(log($total)/log(65536)*100).'%';
                                }
                        break;
-                       case "rank_freq":
+                       case 'rank_freq':       // Based on frequency
                                $max = 10000;
-                               $total = t3lib_div::intInRange($row["order_val"],0,$max);
+                               $total = t3lib_div::intInRange($row['order_val'],0,$max);
 #                              debug($total);
-                               return ceil(log($total)/log($max)*100)."%";
+                               return ceil(log($total)/log($max)*100).'%';
                        break;
-                       case "crdate":
-                               return $this->cObj->calcAge(time()-$row["item_crdate"],0); // ,$conf["age"]
+                       case 'crdate':  // Based on creation date
+                               return $this->cObj->calcAge(time()-$row['item_crdate'],0); // ,$conf['age']
                        break;
-                       case "mtime":
-                               return $this->cObj->calcAge(time()-$row["item_mtime"],0); // ,$conf["age"]
+                       case 'mtime':   // Based on modification time
+                               return $this->cObj->calcAge(time()-$row['item_mtime'],0); // ,$conf['age']
                        break;
                        default:        // fx. title
-#                              return "[rating...]";
-                               return "&nbsp;";
+                               return '&nbsp;';
                        break;
                }
        }
 
        /**
         * Returns the resume for the search-result.
-        * If noMarkup is NOT set, then the index_fulltext table is used to select the content of the page, split it with regex to display the search words in the text.
+        *
+        * @param       array           Search result row
+        * @param       boolean         If noMarkup is false, then the index_fulltext table is used to select the content of the page, split it with regex to display the search words in the text.
+        * @param       integer         String length
+        * @return      string          HTML string             ...
         */
        function makeDescription($row,$noMarkup=0,$lgd=180)     {
-               if ($row["show_resume"])        {
-       #debug($row)    ;
+               if ($row['show_resume'])        {
                        if (!$noMarkup) {
-                               $markedSW = "";
+                               $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"]);
+                                       $markedSW = $this->markupSWpartsOfString($ftdrow['fulltextdata']);
                                }
                                $GLOBALS['TYPO3_DB']->sql_free_result($res);
                        }
 
-                       return $this->utf8_to_currentCharset(htmlspecialchars(t3lib_div::fixed_lgd(str_replace("&nbsp;"," ",$row["item_description"]),$lgd)).(trim($markedSW)?" ... ".$markedSW:"")).'
-                               <BR><img src=clear.gif width=1 height=5>';
+                       if (trim($markedSW))    {
+                               return $this->utf8_to_currentCharset($markedSW);
+                       } else {
+                               $outputStr = $GLOBALS['TSFE']->csConvObj->crop('utf-8',$row['item_description'],$lgd);
+                               $outputStr = htmlspecialchars($outputStr);
+
+                               return $this->utf8_to_currentCharset($outputStr);
+                       }
                } else {
-                       return '<font color="#666666">'.$this->pi_getLL("res_noResume").'
-                               <BR><img src=clear.gif width=1 height=5></font>';
+                       return '<span class="noResume">'.$this->pi_getLL('res_noResume','',1).'</span>';
                }
        }
 
        /**
         * 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.
+        * @return      string          Processed content.
         */
        function markupSWpartsOfString($str)    {
-               $str = str_replace("&nbsp;"," ",t3lib_parsehtml::bidir_htmlspecialchars($str,-1));
-               reset($this->sWArr);
-#debug($this->sWArr);
-               $swForReg=array();
-               while(list(,$d)=each($this->sWArr))     {
-                       $swForReg[]=quotemeta($d["sword"]);
+
+                       // Init:
+               $str = str_replace('&nbsp;',' ',t3lib_parsehtml::bidir_htmlspecialchars($str,-1));
+               $swForReg = array();
+
+                       // Prepare search words for regex:
+               foreach($this->sWArr as $d)     {
+                       $swForReg[] = quotemeta($d['sword']);
                }
-               $regExString = implode("|",$swForReg);
+               $regExString = implode('|',$swForReg);
 
-               $noAlph="[^[:alnum:]]";
-               $theType = (string)$this->piVars["type"];
+                       // Build regex:
+               #$noAlph = '[^[:alnum:]]';
+               $theType = (string)$this->piVars['type'];
                switch($theType)        {
-                       case "1":
-                       case "20":
+                       case '1':
+                       case '20':
                                // Nothing...
                        break;
-                       case "2":
-                               $regExString = $noAlph."(".$regExString.")";
+                       case '2':
+                               $regExString = $noAlph.'('.$regExString.')';
                        break;
-                       case "3":
-                               $regExString = "(".$regExString.")".$noAlph;
+                       case '3':
+                               $regExString = '('.$regExString.')'.$noAlph;
                        break;
-                       case "10":
+                       case '10':
                        break;
                        default:
-                               $regExString = $noAlph."(".$regExString.")".$noAlph;
+                               $regExString = $noAlph.'('.$regExString.')'.$noAlph;
                        break;
                }
-#debug(array($regExString));
-
-               $parts = spliti($regExString,$str,6);
-#debug($parts);
-               reset($parts);
-               $strLen=0;
-
-               $snippets=array();
-               while(list($k,$strP)=each($parts))      {
-                       if ($k+1<count($parts)) {
-                               $strLen+=strlen($strP);
-                               $reg=array();
-                               eregi("^".$regExString,substr($str,$strLen,50),$reg);
-
-                               $snippets[] = array(
-#                                      substr($str,$strLen-50,50),
-                                       substr($parts[$k],-50),
-                                       substr($str,$strLen,strlen($reg[0])),
-                                       substr($parts[$k+1],0,50)
-#                                      substr($str,$strLen+strlen($reg[0]),50),
-                               );
 
-                               $strLen+=strlen($reg[0]);
-#                              debug($reg);
-                       }
-               }
+                       // Split and combine:
+               $parts = preg_split("/".$regExString."/i", ' '.$str.' ', 20000, PREG_SPLIT_DELIM_CAPTURE);
+
+                       // Constants:
+               $postPreLgd = 60;
+               $postPreLgd_offset = 5;
+               $summaryMax = 300;
+               $divider = ' ... ';
+
+                       // Variable:
+               $summaryLgd = 0;
+               $output = array();
 
-               reset($snippets);
-               $content=array();
-               while(list(,$d)=each($snippets))        {
-                       $content[]=htmlspecialchars($d[0]).'<span'.$this->pi_classParam("redMarkup").'>'.htmlspecialchars($d[1]).'</span>'.htmlspecialchars($d[2]);
+                       // Shorten in-between strings:
+               foreach($parts as $k => $strP)  {
+                       if (($k%2)==0)  {
+
+                                       // Find length of the summary part:
+                               $strLen = $GLOBALS['TSFE']->csConvObj->strlen('utf-8', $parts[$k]);
+                               $summaryLgd+= $strLen;
+                               $output[$k] = $parts[$k];
+
+                                       // 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)));
+                                       }
+                               } 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;
+                                       }
+                               } 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)).
+                                                                               $divider.
+                                                                               ereg_replace('^[^[:space:]]+[[:space:]]','',$GLOBALS['TSFE']->csConvObj->crop('utf-8',$parts[$k],-($postPreLgd-$postPreLgd_offset)));
+                                       }
+                               }
+
+                                       // Protect output:
+                               $output[$k] = htmlspecialchars($output[$k]);
+
+                                       // If summary lgd is exceed, break the process:
+                               if ($summaryLgd > $summaryMax)  {
+                                       break;
+                               }
+                       } else {
+                               $summaryLgd+= $GLOBALS['TSFE']->csConvObj->strlen('utf-8',$strP);
+                               $output[$k] = '<span class="tx-indexedsearch-redMarkup">'.htmlspecialchars($parts[$k]).'</span>';
+                       }
                }
 
-               return implode(" ... ",$content);
+                       // Return result:
+               return implode('',$output);
        }
 
        /**
         * Returns the title of the search result row
+        *
+        * @param       array           Result row
+        * @return      string          Title from row
         */
        function makeTitle($row)        {
-               $add="";
-               if ($row["item_type"]==2)       {
-                       $dat = unserialize($row["cHashParams"]);
-                       $pp=explode("-",$dat["key"]);
+               $add = '';
+
+               if ($this->multiplePagesType($row['item_type']))        {
+                       $dat = unserialize($row['cHashParams']);
+
+                       $pp = explode('-',$dat['key']);
                        if ($pp[0]!=$pp[1])     {
-                               $add=", ".$this->pi_getLL("word_pages")." ".$dat["key"];
-                       } else $add=", ".$this->pi_getLL("word_page")." ".$pp[0];
+                               $add=', '.$this->pi_getLL('word_pages').' '.$dat['key'];
+                       } else $add=', '.$this->pi_getLL('word_page').' '.$pp[0];
                }
-               return $this->utf8_to_currentCharset(htmlspecialchars(t3lib_div::fixed_lgd($row["item_title"],50))).$add;
+
+               $outputString = $GLOBALS['TSFE']->csConvObj->crop('utf-8',$row['item_title'],50,'...');
+
+               return $this->utf8_to_currentCharset(htmlspecialchars($outputString)).$add;
        }
 
        /**
         * Returns the info-string in the bottom of the result-row display (size, dates, path)
+        *
+        * @param       array           Result row
+        * @param       array           Template array to modify
+        * @return      array           Modified template array
         */
-       function makeInfo($row) {
-               $lines=array();
-               $lines[]=$this->pi_getLL("res_size")." ".t3lib_div::formatSize($row["item_size"])."";
-               $lines[]=$this->pi_getLL("res_created")." ".date("d-m-y",$row["item_crdate"])."";
-               $lines[]=$this->pi_getLL("res_modified")." ".date("d-m-y H:i",$row["item_mtime"])."";
-               $out = implode(" - ",$lines);
-               $pathId = $row["data_page_id"]?$row["data_page_id"]:$row["page_id"];
-               $pathMP = $row["data_page_id"]?$row["data_page_mp"]:"";
-               $out.="<BR>".$this->pi_getLL("res_path")." ".$this->linkPage($pathId,htmlspecialchars($this->getPathFromPageId($pathId,$pathMP)));
-               return $out;
+       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']).'';
+
+               $pathId = $row['data_page_id']?$row['data_page_id']:$row['page_id'];
+               $pathMP = $row['data_page_id']?$row['data_page_mp']:'';
+
+               $pI = parse_url($row['data_filename']);
+               if ($pI['scheme'])      {
+                       $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));
+               }
+
+               return $tmplArray;
        }
 
        /**
-        * Returns the info-string in the bottom of the result-row display (size, dates, path)
+        * Returns configuration from TypoScript for result row based on ID / location in page tree!
+        *
+        * @param       array           Result row
+        * @return      array           Configuration array
         */
        function getSpecialConfigForRow($row)   {
-               $pathId = $row["data_page_id"]?$row["data_page_id"]:$row["page_id"];
-               $pathMP = $row["data_page_id"]?$row["data_page_mp"]:"";
+               $pathId = $row['data_page_id'] ? $row['data_page_id'] : $row['page_id'];
+               $pathMP = $row['data_page_id'] ? $row['data_page_mp'] : '';
 
                $rl = $this->getRootLine($pathId,$pathMP);
-               $specConf = $this->conf["specConfs."]["0."];
+               $specConf = $this->conf['specConfs.']['0.'];
                if (is_array($rl))      {
-                       reset($rl);
-                       while(list(,$dat)=each($rl))    {
-                               if (is_array($this->conf["specConfs."][$dat["uid"]."."]))       {
-                                       $specConf = $this->conf["specConfs."][$dat["uid"]."."];
+                       foreach($rl as $dat)    {
+                               if (is_array($this->conf['specConfs.'][$dat['uid'].'.']))       {
+                                       $specConf = $this->conf['specConfs.'][$dat['uid'].'.'];
                                        break;
                                }
                        }
@@ -1429,43 +1808,69 @@ class tx_indexedsearch extends tslib_pibase {
 
        /**
         * Returns the HTML code for language indication.
+        *
+        * @param       array           Result row
+        * @return      string          HTML code for result row.
         */
        function makeLanguageIndication($row)   {
-               if ($row["item_type"]==0)       {
-                       switch($row["sys_language_uid"])        {
-                                       // OBVIOUSLY this will not work generally. First we need to know WHICH flag is used for WHICH language-uid. This just shows the concept works.
-                               case 1:
-                                       return '<img src="tslib/media/flags/flag_dk.gif" width="21" height="13" border="0" alt="Danish">';
-                               break;
-                               case 2:
-                                       return '<img src="tslib/media/flags/flag_de.gif" width="21" height="13" border="0" alt="German">';
-                               break;
-                               default:
-                               #       return '<img src="tslib/media/flags/flag_uk.gif" width="21" height="13" border="0" alt="English - default">';
-                               break;
+
+                       // If search result is a TYPO3 page:
+               if ((string)$row['item_type']==='0')    {
+
+                               // If TypoScript is used to render the flag:
+                       if (is_array($this->conf['flagRendering.']))    {
+                               $this->cObj->setCurrentVal($row['sys_language_uid']);
+                               return $this->cObj->cObjGetSingle($this->conf['flagRendering'],$this->conf['flagRendering.']);
+                       } else { // ... otherwise, get flag from sys_language record:
+
+                                       // Get sys_language record
+                               $rowDat = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'sys_language', 'uid='.intval($row['sys_language_uid']).' '.$this->cObj->enableFields('sys_language'));
+
+                                       // Flag code:
+                               $flag = $rowDat[0]['flag'];
+                               if ($flag)      {
+                                       $file = 't3lib/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;
+                                       }
+                               }
                        }
                }
-               return "&nbsp;";
+               return '&nbsp;';
        }
 
        /**
         * Returns the HTML code for the locking symbol.
+        * NOTICE: Requires a call to ->getPathFromPageId() first in order to work (done in ->makeInfo() by calling that first)
+        *
+        * @param       integer         Page id for which to find answer
+        * @return      string          <img> tag if access is limited.
         */
        function makeAccessIndication($id)      {
                if (is_array($this->fe_groups_required[$id]) && count($this->fe_groups_required[$id]))  {
-                       return '<img src="'.t3lib_extMgm::siteRelPath("indexed_search").'pi/res/locked.gif" width="12" height="15" vspace=5 title="'.sprintf($this->pi_getLL("res_memberGroups"),implode(",",array_unique($this->fe_groups_required[$id]))).'">';
+                       return '<img src="'.t3lib_extMgm::siteRelPath('indexed_search').'pi/res/locked.gif" width="12" height="15" vspace="5" title="'.sprintf($this->pi_getLL('res_memberGroups','',1),implode(',',array_unique($this->fe_groups_required[$id]))).'" alt="" />';
                }
        }
 
        /**
         * Links the $str to page $id
+        *
+        * @param       integer         Page id
+        * @param       string          Title String to link
+        * @param       array           Result row
+        * @return      string          <A> tag wrapped title string.
         */
        function linkPage($id,$str,$row=array())        {
-#              return $str;
-               $urlParameters = unserialize($row["cHashParams"]);
-#              $urlParameters["cHash"] = t3lib_div::shortMD5(serialize($row["cHashParams"]));  // not needed - it's there already...
-#debug($urlParameters);
 
+                       // Parameters for link:
+               $urlParameters = 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'];
 
                        // 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]))      {
@@ -1478,89 +1883,97 @@ class tx_indexedsearch extends tslib_pibase {
                        $firstDom = current($this->domain_records[$id]);
                        $scheme = t3lib_div::getIndpEnv('TYPO3_SSL') ? 'https://' : 'http://';
 
-                       $addParams="";
+                       $addParams = '';
                        if (is_array($urlParameters))   {
                                if (count($urlParameters))      {
                                        reset($urlParameters);
                                        while(list($k,$v)=each($urlParameters)) {
-                                               $addParams.="&".$k."=".rawurlencode($v);
+                                               $addParams.= '&'.$k.'='.rawurlencode($v);
                                        }
                                }
                        }
 
-                       return '<a href="'.$scheme.$firstDom.'/index.php?id='.$id.$addParams.'" target="'.$this->conf["search."]["detect_sys_domain_records."]["target"].'">'.htmlspecialchars($str).'</a>';
+                       return '<a href="'.$scheme.$firstDom.'/index.php?id='.$id.$addParams.'" target="'.$this->conf['search.']['detect_sys_domain_records.']['target'].'">'.htmlspecialchars($str).'</a>';
                } else {
-                       return $this->pi_linkToPage($str,$id,$this->conf["result_link_target"],$urlParameters);
+                       return $this->pi_linkToPage($str,$id,$this->conf['result_link_target'],$urlParameters);
                }
        }
 
        /**
         * Returns the path to the page $id
+        *
+        * @param       integer         Page ID
+        * @param       string          MP variable content.
+        * @return      string          Root line for result.
         */
-       function getRootLine($id,$pathMP="")    {
-               $identStr = $id."|".$pathMP;
+       function getRootLine($id,$pathMP='')    {
+               $identStr = $id.'|'.$pathMP;
 
                if (!isset($this->cache_path[$identStr]))       {
-                       $this->cache_rl[$identStr] = $GLOBALS["TSFE"]->sys_page->getRootLine($id,$pathMP);
+                       $this->cache_rl[$identStr] = $GLOBALS['TSFE']->sys_page->getRootLine($id,$pathMP);
                }
                return $this->cache_rl[$identStr];
        }
 
        /**
         * Gets the first sys_domain record for the page, $id
+        *
+        * @param       integer         Page id
+        * @return      string          Domain name
         */
        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 ereg_replace('\/$','',$row['domainName']);
        }
 
        /**
         * Returns the path to the page $id
+        *
+        * @param       integer         Page ID
+        * @param       string          MP variable content
+        * @return      string          Path
         */
-       function getPathFromPageId($id,$pathMP="")      {
-                       // Here I imagine some caching...
-               $identStr = $id."|".$pathMP;
+       function getPathFromPageId($id,$pathMP='')      {
+
+               $identStr = $id.'|'.$pathMP;
 
                if (!isset($this->cache_path[$identStr]))       {
-                       $this->fe_groups_required[$id]=array();
-                       $this->domain_records[$id]=array();
+                       $this->fe_groups_required[$id] = array();
+                       $this->domain_records[$id] = array();
                        $rl = $this->getRootLine($id,$pathMP);
-                       $hitRoot=0;
-                       $path="";
+                       $hitRoot = 0;
+                       $path = '';
                        if (is_array($rl) && count($rl))        {
                                reset($rl);
                                while(list($k,$v)=each($rl))    {
                                                // Check fe_user
-                                       if ($v["fe_group"] && ($v["uid"]==$id || $v["extendToSubpages"]))       {
-                                               $this->fe_groups_required[$id][]=$v["fe_group"];
+                                       if ($v['fe_group'] && ($v['uid']==$id || $v['extendToSubpages']))       {
+                                               $this->fe_groups_required[$id][]=$v['fe_group'];
                                        }
                                                // Check sys_domain.
-                                       if ($this->conf["search."]["detect_sys_domain_records"])        {
-                                               $sysDName = $this->getFirstSysDomainRecordForPage($v["uid"]);
+                                       if ($this->conf['search.']['detect_sys_domain_records'])        {
+                                               $sysDName = $this->getFirstSysDomainRecordForPage($v['uid']);
                                                if ($sysDName)  {
-                                                       $this->domain_records[$id][]=$sysDName;
-#                                                      debug($sysDName);
+                                                       $this->domain_records[$id][] = $sysDName;
                                                                // Set path accordingly:
-                                                       $path=$sysDName.$path;
+                                                       $path = $sysDName.$path;
                                                        break;
                                                }
                                        }
 
                                                // Stop, if we find that the current id is the current root page.
-                                       if ($v["uid"]==$GLOBALS["TSFE"]->config["rootLine"][0]["uid"])          {
+                                       if ($v['uid']==$GLOBALS['TSFE']->config['rootLine'][0]['uid'])          {
                                                break;
                                        }
-                                       $path="/".$v["title"].$path;
+                                       $path = '/'.$v['title'].$path;
                                }
                        }
 
-#                      $pageRec = $GLOBALS["TSFE"]->sys_page->checkRecord("pages",$id);
-#                      $path.="/".$pageRec["title"];
                        $this->cache_path[$identStr] = $path;
 
-                       if (is_array($this->conf["path_stdWrap."]))     {
-                               $this->cache_path[$identStr] = $this->cObj->stdWrap($this->cache_path[$identStr], $this->conf["path_stdWrap."]);
+                       if (is_array($this->conf['path_stdWrap.']))     {
+                               $this->cache_path[$identStr] = $this->cObj->stdWrap($this->cache_path[$identStr], $this->conf['path_stdWrap.']);
                        }
                }
 
@@ -1568,62 +1981,33 @@ class tx_indexedsearch extends tslib_pibase {
        }
 
        /**
-        * Returns a results browser
-        */
-       function pi_list_browseresults($showResultCount=1,$addString="",$addPart="")    {
-
-                       // 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();
-
-                       // Make browse-table/links:
-               if ($pointer>0) {
-                       $links[]='<td><p>'.$this->makePointerSelector_link($this->pi_getLL("pi_list_browseresults_prev","< Previous"),$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")." ".($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 >"),$pointer+1).'</p></td>';
-               }
-
-               $pR1 = $pointer*$results_at_a_time+1;
-               $pR2 = $pointer*$results_at_a_time+$results_at_a_time;
-               $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>")),
-                               $pR1,
-                               min(array($this->internal["res_count"],$pR2)),
-                               $this->internal["res_count"]
-                               ).$addString.'</P>':''
-                       ).$addPart.
-               '<table>
-                       <tr>'.implode("",$links).'</tr>
-               </table></DIV>';
-               return $sTables;
-       }
-
-       /**
         * Return the menu of pages used for the selector.
+        *
+        * @param       integer         Page ID for which to return menu
+        * @return      array           Menu items (for making the section selector box)
         */
        function getMenu($id)   {
-               if ($this->conf["show."]["LxALLtypes"]) {
+               if ($this->conf['show.']['LxALLtypes']) {
                        $output = Array();
                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('title,uid', 'pages', 'pid='.intval($id).$this->cObj->enableFields('pages'), '', 'sorting');
                        while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))       {
-                               $output[$row["uid"]]=$GLOBALS["TSFE"]->sys_page->getPageOverlay($row);
+                               $output[$row['uid']] = $GLOBALS['TSFE']->sys_page->getPageOverlay($row);
                        }
                        return $output;
                } else {
-                       return $GLOBALS["TSFE"]->sys_page->getMenu($id);
+                       return $GLOBALS['TSFE']->sys_page->getMenu($id);
                }
        }
 
+       /**
+        * Returns if an item type is a multipage item type
+        *
+        * @param       string          Item type
+        * @return      boolean         True if multipage capable
+        */
+       function multiplePagesType($item_type)  {
+               return is_object($this->external_parsers[$item_type]) && $this->external_parsers[$item_type]->isMultiplePageExtension($item_type);
+       }
 
        /**
         * Converts the input string from utf-8 to the backend charset.
@@ -1635,10 +2019,28 @@ class tx_indexedsearch extends tslib_pibase {
                return $GLOBALS['TSFE']->csConv($str,'utf-8');
        }
 
+       /**
+        * Returns an object reference to the hook object if any
+        *
+        * @param       string          Name of the function you want to call / hook key
+        * @return      object          Hook object, if any. Otherwise null.
+        */
+       function &hookRequest($functionName)    {
+               global $TYPO3_CONF_VARS;
+
+                       // Hook: menuConfig_preProcessModMenu
+               if ($TYPO3_CONF_VARS['EXTCONF']['indexed_search']['pi1_hooks'][$functionName]) {
+                       $hookObj = &t3lib_div::getUserObj($TYPO3_CONF_VARS['EXTCONF']['indexed_search']['pi1_hooks'][$functionName]);
+                       if (method_exists ($hookObj, $functionName)) {
+                               $hookObj->pObj = &$this;
+                               return $hookObj;
+                       }
+               }
+       }
 }
 
-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"]);
-}
 
+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']);
+}
 ?>
index 410204c..54c4bee 100755 (executable)
@@ -23,9 +23,6 @@ $LOCAL_LANG = Array (
                'opt_media_-1' => 'All media',
                'opt_media_0' => 'Internal pages',
                'opt_media_-2' => 'All External',
-               'opt_media_1' => 'HTML',
-               'opt_media_2' => 'PDF',
-               'opt_media_3' => 'MS Word',
                'opt_order_rank_flag' => 'Weight/Frequency',
                'opt_order_rank_freq' => 'Frequency',
                'opt_order_rank_first' => 'Close to top',
@@ -88,6 +85,8 @@ $LOCAL_LANG = Array (
                'local_operator_AND' => 'AND',
                'local_operator_OR' => 'OR',
                'local_operator_NOT' => 'NOT',
+               'makerating_addToCurrentSearch' => 'Add to current search words',
+               'maketitle_matches' => 'matches',
        ),
        'dk' => Array (
                'submit_button_label' => 'Søg',
@@ -380,7 +379,7 @@ OG, ELLER og IKKE er kommandoord som overskriver standard s
                'rules_header' => 'Regole:',
                'rules_text' => 'Sono accettate solo parole con due o più caratteri, per un massimo di 200 caratteri totali.
 Lo spazio è usato per separare le parole, "" può essere usato per cercare un\'intera stringa.
-AND, OR e NOT possono essere usati prefissi alle parole da cercare. 
+AND, OR e NOT possono essere usati prefissi alle parole da cercare.
 +/|/- corrispondono agli operatori AND, OR e NOT.
 Tutte le parole sono convertite in caratteri minuscoli.',
                'searchFor' => 'Cerca',
@@ -1336,7 +1335,7 @@ Sve tra
                'form_match' => 'Illeszkedés:',
                'form_style' => 'Stílus:',
                'rules_header' => 'Szabályok:',
-               'rules_text' => 'Csak 2 vagy több karakterbõl álló szavak elfogadottak. 
+               'rules_text' => 'Csak 2 vagy több karakterbõl álló szavak elfogadottak.
 Max 200 karakter összesen.
 A szóköz a szavak elválasztására szolgál, "" használható egész szöveg keresésre (nem indexelt keresés ekkor)
 ÉS, VAGY és NEM prefix szavak, felülírják az alapértelmezett operátorokat