Index: t3lib/config_default.php
===================================================================
--- t3lib/config_default.php	(Revision 157)
+++ t3lib/config_default.php	(Revision 159)
@@ -176,6 +176,7 @@
 			'SC_alt_file_navframe::expandCollapse' => 'typo3/alt_file_navframe.php:SC_alt_file_navframe->ajaxExpandCollapse',
 			't3lib_TCEforms_inline::createNewRecord'		=> 't3lib/class.t3lib_tceforms_inline.php:t3lib_TCEforms_inline->processAjaxRequest',
 			't3lib_TCEforms_inline::setExpandedCollapsedState'	=> 't3lib/class.t3lib_tceforms_inline.php:t3lib_TCEforms_inline->processAjaxRequest',
+			't3lib_TCEforms_suggest::searchRecord' => 't3lib/classes/class.t3lib_tceforms_suggest.php:t3lib_TCEforms_suggest->processAjaxRequest',
 			'ShortcutMenu::getGroups'              => 'typo3/classes/class.shortcutmenu.php:ShortcutMenu->getAjaxShortcutGroups',
 			'ShortcutMenu::saveShortcut'           => 'typo3/classes/class.shortcutmenu.php:ShortcutMenu->setAjaxShortcut',
 			'ShortcutMenu::render'                 => 'typo3/classes/class.shortcutmenu.php:ShortcutMenu->renderAjax',
Index: t3lib/class.t3lib_tceforms.php
===================================================================
--- t3lib/class.t3lib_tceforms.php	(Revision 157)
+++ t3lib/class.t3lib_tceforms.php	(Revision 159)
@@ -183,6 +183,7 @@
 
 require_once(PATH_t3lib.'class.t3lib_diff.php');
 require_once(PATH_t3lib.'class.t3lib_tceforms_inline.php');
+require_once(PATH_t3lib.'classes/class.t3lib_tceforms_suggest.php');
 
 
 
@@ -364,6 +365,11 @@
 		if (!isset($GLOBALS['ajaxID']) || strpos($GLOBALS['ajaxID'], 't3lib_TCEforms_inline::')!==0) {
 			$this->inline = t3lib_div::makeInstance('t3lib_TCEforms_inline');
 		}
+			// Create instance of t3lib_TCEforms_suggest only if this a non-Suggest-AJAX call: 
+		if (!isset($GLOBALS['ajaxID']) || strpos($GLOBALS['ajaxID'], 't3lib_TCEforms_suggest::')!==0) {
+			$this->suggest = t3lib_div::makeInstance('t3lib_TCEforms_suggest');
+		}
+		
 
 			// Prepare user defined objects (if any) for hooks which extend this function:
 		$this->hookObjectsMainFields = array();
@@ -398,6 +404,7 @@
 		$this->titleLen = $BE_USER->uc['titleLen'];		// @deprecated
 
 		$this->inline->init($this);
+		$this->suggest->init($this);
 	}
 
 
@@ -2068,6 +2075,17 @@
 				if (!$disabled && $show_thumbs)	{
 					$thumbsnail = implode('<br />',$imgs);
 				}
+				
+				$hideSuggest = $PA['fieldConf']['config']['hideSuggestByDefault'];
+				if (isset($GLOBALS['BE_USER']->userTS['options.']['suggest.']['hideSuggestByDefault'])) {
+					$hideSuggest = (bool)$GLOBALS['BE_USER']->userTS['options.']['suggest.']['hideSuggestByDefault'];
+				}
+				
+					// has to be rendered here because when creating the whole form we don't have
+					// all neccessary information available for calling the function
+				if ($config['useSuggest']) {
+					$suggestSelector = $this->suggest->renderSuggestSelector($PA['itemFormElName'], $table, $field, $row, $config, $hideSuggest, $this);
+				}
 
 					// Creating the element:
 				$params = array(
@@ -2078,7 +2096,10 @@
 					'style' => isset($config['selectedListStyle']) ? ' style="'.htmlspecialchars($config['selectedListStyle']).'"' : ' style="'.$this->defaultMultipleSelectorStyle.'"',
 					'info' => $info,
 					'thumbnails' => $thumbsnail,
-					'readOnly' => $disabled
+					'readOnly' => $disabled,
+					'hideSuggest' => $hideSuggest,
+					'suggestBoxPosition' => $PA['fieldConf']['config']['suggestBoxPosition'],
+					'suggestSelector' => $suggestSelector
 				);
 				$item.= $this->dbFileIcons($PA['itemFormElName'],'db',implode(',',$tempFT),$itemArray,'',$params,$PA['onFocus'],$table,$field,$row['uid']);
 
@@ -3318,6 +3339,18 @@
 		if (!$selector)	{
 			$selector = '<select ' . ($params['noList'] ? 'style="display: none"' : 'size="'.$sSize.'"'.$this->insertDefStyle('group')).' multiple="multiple" name="'.$fName.'_list" '.$onFocus.$params['style'].$disabled.'>'.implode('',$opt).'</select>';
 		}
+		
+		if ($params['suggestSelector']) {
+			switch ($params['suggestBoxPosition']) {
+				case 'right':
+					$params['thumbnails'] = $params['suggestSelector'].$params['thumbnails'];
+					break;
+					
+				default:
+					$selector .= $params['suggestSelector'];
+					break;
+			}
+		}
 
 
 		$icons = array(
@@ -3340,6 +3373,12 @@
 						'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/insert3.gif','width="14" height="14"').' border="0" '.t3lib_BEfunc::titleAltAttrib($this->getLL('l_browse_'.($mode=='file'?'file':'db'))).' />'.
 						'</a>';
 			}
+			if ($params['hideSuggest'])	{
+				$aOnClick='new Effect.Appear("suggest-'.$table.'-'.$field.'-'.$uid.'"); new Effect.Fade("suggestlink-'.$table.'-'.$field.'-'.$uid.'");';
+				$icons['R'][]='<a href="#" onclick="'.htmlspecialchars($aOnClick).'" id="suggestlink-'.$table.'-'.$field.'-'.$uid.'">'.
+						'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/group_suggest.gif','width="14" height="14"').' border="0" '.t3lib_BEfunc::titleAltAttrib($this->getLL('l_suggest')).' />'.
+						'</a>';
+			}
 			if (!$params['dontShowMoveIcons'])	{
 				if ($sSize>=5)	{
 					$icons['L'][]='<a href="#" onclick="setFormValueManipulate(\''.$fName.'\',\'Top\'); return false;">'.
@@ -4946,13 +4985,16 @@
 
 				// if IRRE fields were processed, add the JavaScript functions:
 			if ($this->inline->inlineCount) {
-				$jsFile[] = '<script src="'.$this->backPath.'contrib/scriptaculous/scriptaculous.js" type="text/javascript"></script>';
 				$jsFile[] = '<script src="'.$this->backPath.'../t3lib/jsfunc.inline.js" type="text/javascript"></script>';
 				$out .= '
 				inline.setPrependFormFieldNames("'.$this->inline->prependNaming.'");
 				inline.setNoTitleString("'.addslashes(t3lib_BEfunc::getNoRecordTitle(true)).'");
 				';
 			}
+				// if Suggest fields were processed, add the JS functions:
+			if ($this->suggest->suggestCount > 0) {
+				$jsFile[] = '<script src="'.$this->backPath.'../t3lib/js/jsfunc.suggest.js" type="text/javascript"></script>';
+			}
 
 				// Toggle icons:
 			$toggleIcon_open = '<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/pil2down.gif','width="12" height="7"').' hspace="2" alt="Open" title="Open" />';
Index: t3lib/js/jsfunc.suggest.js
===================================================================
--- t3lib/js/jsfunc.suggest.js	(Revision 0)
+++ t3lib/js/jsfunc.suggest.js	(Revision 159)
@@ -0,0 +1,82 @@
+/***************************************************************
+*  AJAX selectors for TCEforms
+*
+* $Id:$
+*
+*  Copyright notice
+*
+*  (c) 2007 Andreas Wolf <typo3@andreaswolf.info>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Class for JS handling of suggest fields in TCEforms.
+ * 
+ * @author  Andreas Wolf <typo3@andreaswolf.info>
+ */ 
+var suggest = {
+	/**
+	 * Wrapper for script.aculo.us' Autocompleter functionality: Assigns a new autocompletion object to
+	 * the input field of a given Suggest selector.
+	 * 
+	 * @param  string  objectId  The ID of the object to assign the completer to
+	 * @param  string  table     The table of the record which is currently edited
+	 * @param  string  field     The field which is currently edited
+	 * @param  integer uid       The uid of the record which is currently edited
+	 * @param  integer pid       The pid of the record which is currently edited
+	 * @return void
+	 */
+	createSuggestField: function(objectId, table, field, uid, pid) {
+		new Ajax.Autocompleter(
+			objectId+"Suggest", 
+			objectId+"SuggestChoices",
+			"ajax.php",
+			{
+				paramName: "value",
+				minChars: 2,
+				updateElement: suggest.addElementToList,
+				parameters: 'ajaxID=t3lib_TCEforms_suggest::searchRecord&table='+table+'&field='+field+'&formfield='+objectId+'&uid='+uid+'&pid='+pid
+			}
+		);
+	},
+	
+	/**
+	 * Adds an element to the list of items in a group selector.
+	 * 
+	 * @param  object  item  The item to add to the list (usually an li element)
+	 * @return void
+	 */
+	addElementToList: function(item) {
+		arr = item.id.split('-');
+		ins_table = arr[0];
+		ins_uid = arr[1];
+		rec_table = arr[2];
+		rec_uid = arr[3];
+		rec_field = arr[4];
+		
+		setFormValueFromBrowseWin('data['+rec_table+']['+rec_uid+']['+rec_field+']',ins_table+'_'+ins_uid, item.firstChild.textContent);
+		TBE_EDITOR.fieldChanged(rec_table,rec_uid,rec_field,'data['+rec_table+']['+rec_uid+']['+rec_field+']');
+		
+		suggest = document.getElementById('data['+rec_table+']['+rec_uid+']['+rec_field+']Suggest');
+		suggest.value = '';
+	}
+}
+
+
+/*]]>*/
\ Kein Zeilenvorschub am Ende der Datei
Index: t3lib/classes/class.t3lib_tceforms_suggest.php
===================================================================
--- t3lib/classes/class.t3lib_tceforms_suggest.php	(Revision 0)
+++ t3lib/classes/class.t3lib_tceforms_suggest.php	(Revision 159)
@@ -0,0 +1,212 @@
+<?php
+
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2007 Andreas Wolf <typo3@andreaswolf.info>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+/**
+ * AJAX functions for use in TCEforms
+ *
+ * $Id:$
+ *
+ * @author Andreas Wolf <typo3@andreaswolf.info>
+ */
+
+class t3lib_TCEforms_suggest {
+	public $suggestCount = 0;					// count the number of ajax selectors used
+
+
+	/**
+	 * Initialize an instance of t3lib_TCEforms_suggest
+	 *
+	 * @param  t3lib_TCEforms  $tceForms  Reference to an TCEforms instance
+	 * @return void
+	 */
+	public function init(&$tceForms) {
+		$this->TCEformsObj =& $tceForms;
+		$this->backPath =& $tceForms->backPath;
+	}
+	
+	/**
+	 * Renders an ajax-enabled text field. Also adds required JS
+	 *
+	 * @param  string  $fieldname   The fieldname in the form
+	 * @param  string  $table       The table we render this selector for
+	 * @param  string  $field       The field we render this selector for
+	 * @param  array   $row         The row which is currently edited
+	 * @param  array   $config      The TSconfig of the field
+	 * @param  boolean $hideSuggest Whether or not to hide the selector by default
+	 * @return string  The HTML code for the selector
+	 */
+	public function renderSuggestSelector($fieldname, $table, $field, array $row, array $config, $hideSuggest) {
+		$this->suggestCount++;
+		
+		if ($hideSuggest) {
+			$hide = ' style="display:none;"';
+		}
+		
+		// TODO: move CSS to stylesheet
+		$selector = '<div id="suggest-'.$table.'-'.$field.'-'.$row['uid'].'"'.$hide.'>'.$this->getLL('find_record').'
+			<input type="text" id="'.$fieldname.'Suggest" style="width:200px !important;" /></div>
+			<div class="suggest_choices" id="'.$fieldname.'SuggestChoices" style="display:none;"></div>';
+		
+		$this->TCEformsObj->additionalJS_post[] = '
+			suggest.createSuggestField("'.$fieldname.'", "'.$table.'", "'.$field.'", "'.$row['uid'].'", '.$row['pid'].');
+		';
+		
+		return $selector;
+	}
+	
+	/**
+	 * Ajax handler for the "suggest" feature in TCEforms
+	 *
+	 * @param  string  $search    The string to search for in the database
+	 * @param  string  $table     The table which is currently edited
+	 * @param  string  $field     The field which is currently edited
+	 * @param  integer $uid       The uid of the record which is currently edited (may be NEWxxxxxx)
+	 * @param  integer $pid       The pid of the record which is currently edited (always numeric
+	 * @param  string  $formfield The field which is edited
+	 * @return void
+	 */
+	public function processAjaxRequest($params,  &$ajaxObj) {
+		global $TCA, $LANG;
+		
+			// instantiate the global language object here because in AJAX calls it's not available,
+			// but we need it.
+			// @see: typo3/template.php
+		require_once(PATH_typo3.'sysext/lang/lang.php');
+		$LANG = t3lib_div::makeInstance('language');
+		$LANG->init($BE_USER->uc['lang']);
+		
+		
+			// get parameters from $_GET/$_POST
+		$search = t3lib_div::_GP('value');
+		$table = t3lib_div::_GP('table');
+		$field = t3lib_div::_GP('field');
+		$uid = t3lib_div::_GP('uid');
+		$pageId = t3lib_div::_GP('pid');
+		$formfield = t3lib_div::_GP('formfield');
+		
+		
+		t3lib_div::loadTCA($table);
+		
+		if (is_numeric($uid)) {
+				// already existing element, so get the TSconfig of the page itself...
+			if ($table == 'pages') {
+				$pageId = $uid;
+				// ... or the page containing the element
+			} else {
+				$row = t3lib_BEfunc::getRecord($table, $uid);
+				$pageId = $row['pid'];
+			}
+		} // New element, so use given id of parent page (i.e., don't modify it here)
+		
+		$TSconfig = t3lib_BEfunc::getPagesTSconfig($pageId);
+		
+		$queryTables = t3lib_div::trimExplode(',', $TCA[$table]['columns'][$field]['config']['allowed']);
+		
+		$resultRows = array();
+		foreach ($queryTables as $queryTable) {
+			t3lib_div::loadTCA($queryTable);
+			
+				// if the table does not exist, skip it
+			if (count($TCA[$queryTable]) == 0) continue;
+			
+				// merge the configurations of different "levels" to get the working configuration for this table and
+				// field (i.e., go from the most general to the most special configuration)
+			$config = is_array($TSconfig['TCEMAIN.']['default.']['suggest.']) ? 
+			            $TSconfig['TCEMAIN.']['default.']['suggest.'] : array();
+			$config = t3lib_div::array_merge_recursive_overrule($config, 
+			            (is_array($TSconfig['TCEMAIN.'][$queryTable.'.']['suggest.']) ? 
+			              $TSconfig['TCEMAIN.'][$queryTable.'.']['suggest.'] : array()));
+				// use $table instead of $queryTable here because we overlay a config for the input-field here, not for
+				// the queried table
+			$config = t3lib_div::array_merge_recursive_overrule($config, 
+			            (is_array($TSconfig['TCEFORM.'][$table.'.'][$field.'.']['suggest.']) ? 
+			              $TSconfig['TCEFORM.'][$table.'.'][$field.'.']['suggest.'] : array()));
+			$config = t3lib_div::array_merge_recursive_overrule($config, 
+			            (is_array($TSconfig['TCEFORM.'][$table.'.'][$field.'.']['suggest.'][$queryTable.'.']) ? 
+			              $TSconfig['TCEFORM.'][$table.'.'][$field.'.']['suggest.'][$queryTable.'.'] : array()));
+			
+			$class = t3lib_div::makeInstanceClassName($config['suggestClass']);
+			if (!class_exists($class)) {
+				$class = 'suggestDefaultSelector';
+			}
+			$obj = new $class($queryTable, $config);
+			
+			$params = array('value' => $search);
+			$rows = $obj->queryTable($params, $this);
+			
+			
+			if (!$rows) {
+				continue;
+			}
+			$resultRows = t3lib_div::array_merge($resultRows, $rows);
+			unset($rows);
+		}
+		
+		$listItems = array();
+		if (count($resultRows) > 0) {
+				// traverse all found records, ...
+			foreach ($resultRows as $key => $row) {
+				$rowsSort[$key] = $row['text'];
+			}
+				// ... sort them...
+			asort($rowsSort);
+			$rowsSort = array_keys($rowsSort);
+			
+				// ... and put together the selector
+			$returnRows = array();
+			for ($i = 0; $i < 10 && $i < count($resultRows); $i++) {
+				$row = $resultRows[$rowsSort[$i]];
+				$returnRows[] = '<li'.($row['class']!=''?' class="'.$row['class'].'"':'').
+				                ' id="'.$row['table'].'-'.$row['uid'].'-'.$table.'-'.$uid.'-'.$field.
+				                '" style="'.$row['style'].'">'.$row['text'].'</li>';
+			}
+		}
+		if (count($returnRows) > 0) {
+			$list = implode('', $returnRows);
+		} else {
+			$list = '';
+		}
+		
+			// encode the content in utf-8, otherwise it won't be shown correctly in the backend
+		$ajaxObj->addContent(0, $LANG->csConvObj->utf8_encode('<ul>'.$list.'</ul>', $LANG->charSet));
+	}
+	
+	/**
+	 * Returns language label from locallang_core.php
+	 *
+	 * @param	string		The label key
+	 * @return	string		The value of the label, fetched for the current backend language.
+	 */
+	private function getLL($str) {
+		return $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.'.$str);
+	}
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['classes/t3lib/class.t3lib_tceforms_suggest.php'])	{
+	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['classes/t3lib/class.t3lib_tceforms_suggest.php']);
+}
\ Kein Zeilenvorschub am Ende der Datei
Index: typo3/classes/class.suggestDefaultSelector.php
===================================================================
--- typo3/classes/class.suggestDefaultSelector.php	(Revision 0)
+++ typo3/classes/class.suggestDefaultSelector.php	(Revision 159)
@@ -0,0 +1,449 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2007 Andreas Wolf <typo3@andreaswolf.info>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Demo implementation of a handler class for the ajax record selector.
+ * 
+ * Normally other implementations should be inherited from this one. queryTable() should not be overwritten under normal
+ * circumstances.
+ *
+ * @author Andreas Wolf <typo3@andreaswolf.info>
+ *
+ */
+class suggestDefaultSelector {
+	/**
+	 * The name of the table to query
+	 * 
+	 * @var string
+	 */
+	protected $table = '';
+	
+	/**
+	 * The name of the foreign table to query (records from this table will be used for displaying instead of the ones 
+	 * from table)
+	 * 
+	 * @var string
+	 */
+	protected $mmForeignTable = '';
+	
+	/**
+	 * Holds the configuration for the table we query
+	 *
+	 * @var array
+	 */
+	protected $tableConfig = array();
+	
+	/**
+	 * Counter to limit the recursions when querying the table; also needed to choose the range of records to select
+	 *
+	 * @var integer
+	 */
+	protected $recursionCounter = 0;
+	
+	/**
+	 * The select-clause to use when selecting the records (is manipulated and used by different functions, so it has to 
+	 * be a global var)
+	 *
+	 * @var string
+	 */
+	protected $selectClause = '';
+	
+	/**
+	 * Configuration for this selector from TSconfig
+	 *
+	 * @var array
+	 */
+	protected $config = array();
+	
+	/**
+	 * The CSS class(es) to use for rendering the selector
+	 * 
+	 * @var string
+	 */
+	protected $cssClasses = '';
+	
+	
+	
+	/**
+	 * The constructor of this class
+	 *
+	 * @param  string $table
+	 * @param  array  $config  The configuration (TSconfig) to use for this selector
+	 * @return void
+	 */
+	public function __construct($table, $config) {
+		global $TCA;
+		
+		$this->table = $table;
+		
+		$this->config = $config;
+		
+			// Get the configuration for this table
+		$this->tableConfig = $TCA[$table];
+		
+		if ($config['cssClasses'] != '') {
+			$this->cssClasses = $config['cssClasses'];
+		}
+		
+		
+		$depth = intval($config['pidDepth']);
+		
+		$pageIds = t3lib_div::trimExplode(',', $config['pid']);
+		foreach ($pageIds as $pageId) {
+			if ($pageId > 0) {
+				$pagesTemp .= $pageId.',';
+				$pageArr = $this->getAllSubpagesOfPage($pageId, $depth);
+				
+				foreach ($pageArr as $pages) {
+					$pagesTemp .= $pages.',';
+				}
+			}
+		}
+		$this->pages = array_unique(t3lib_div::trimExplode(',', $pagesTemp, true));
+		
+		
+		
+		if ($params['table'] == 'pages') {
+			$this->addWhere = ' AND '.$this->tceforms->readPerms();
+		}
+			// if table is versionized, only get the records from the Live Workspace - the overlay of WS-records is 
+			// done below
+		if ($TCA[$params['table']]['ctrl']['versioningWS'] == true) {
+			$this->addWhere .= ' AND t3ver_wsid=0';
+		}
+	}
+	
+	/**
+	 * Queries a table for records and completely processes them
+	 * 
+	 * Returns a two-dimensional array of almost finished records; the only need to be put into a <li>-structure
+	 * 
+	 * If you subclass this class, you will most likely only want to overwrite the functions called from here, but not
+	 * this function itself
+	 *
+	 * @param  array  $params
+	 * @param  object $ref
+	 * @return array  The fetched and processed rows
+	 */
+	public function queryTable(&$params, &$ref) {
+		global $TYPO3_DB;
+		 
+		$this->params = &$params;
+		
+		$this->start = $this->recursionCounter * 50;
+		
+		$this->prepareSelectStatement();
+		
+		$rows = array();
+		
+		$result = $this->selectRecords();
+		if (!$result) return false;
+		
+		while ($row = $TYPO3_DB->sql_fetch_assoc($result)) {
+				// check if we already have collected 10 records
+			if (count($rows) > 10) break;
+			
+			$this->manipulateRecord($row);
+			
+			$this->makeWorkspaceOverlay($row);
+			
+				// check if the user has access to the record
+			if (!$this->checkRecordAccess($row, $row['uid'])) {
+				continue;
+			}
+			
+			$iconPath = $this->getIcon($row);
+			
+			$uid = ($row['t3ver_oid'] > 0) ? $row['t3ver_oid'] : $row['uid'];
+			
+			$path = $this->getRecordPath($row, $uid);
+			
+			if (strlen($path) > 30) {
+				$croppedPath = $GLOBALS['LANG']->csConvObj->crop($GLOBALS['LANG']->charSet,$path,10).'...'.$GLOBALS['LANG']->csConvObj->crop($GLOBALS['LANG']->charSet,$path,-20);
+			} else {
+				$croppedPath = $path;
+			}
+			
+			
+			
+			$label = $this->getLabel($row);
+			
+			$entry = array(
+				'text' => '<span class="label">'.$label.'</span><span class="uid">('.$uid.')</span><br /><span class="path">'.$croppedPath.'</span>',
+				'table' => ($this->mmForeignTable ? $this->mmForeignTable : $this->table),
+				'path' => $path,
+				'uid' => $uid,
+				'icon' => $iconPath,
+				'style' => 'background-image:url('.$iconPath.');',
+				'class' => $this->cssClasses,
+			);
+			
+			$entry = $this->renderRecord($row, $entry);
+			
+			
+			$rows[$table.'_'.$uid] = $entry;
+		}
+		
+		// if there are less than ten records, call this function again to get more records
+		if (count($rows) < 10 && $TYPO3_DB->sql_num_rows($result) >= 50 && $recursionCounter < 10) {
+			$tmp = self::queryTable($this->params['value'], ++$recursionCounter);
+			$rows = array_merge($tmp, $rows);
+		}
+		
+		return $rows;
+	}
+	
+	/**
+	 * Prepare the statement for selecting the records which will be returned to the selector. May also return some 
+	 * other records (e.g. from a mm-table) which will be used later on to select the real records
+	 *
+	 * @return  void
+	 */
+	protected function prepareSelectStatement() {
+		global $TYPO3_DB;
+		
+		$searchWholePhrase = $this->config['searchWholePhrase'];
+		
+		if (isset($this->pages)) {
+			$this->selectClause = $this->tableConfig['ctrl']['label'].' LIKE \''.($searchWholePhrase ? '%' : '').$TYPO3_DB->escapeStrForLike($this->params['value'], $this->table).'%\' AND deleted=0';
+		}
+		
+		$this->selectClause .= ' AND ('.$this->getPageIdClause($this->pages).')';
+		
+			// add the global clauses to the where-statement
+		$this->selectClause .= $this->addWhere;
+	}
+	
+	/**
+	 * Selects all subpages of one page, optionally only upto a certain level
+	 *
+	 * @param  integer $uid
+	 * @param  integer $depth
+	 */
+	protected function getAllSubpagesOfPage($uid, $depth = 99) {
+		global $TYPO3_DB;
+		
+		$pageIds = array($uid);
+		$level = 0;
+		
+		$pages = array();
+		$pages[$level] = $uid;
+		
+			// check for 
+		while (($depth - $level) >= 0 && $pageIds != '') {
+			++$level;
+			
+			$rows = $TYPO3_DB->exec_SELECTgetRows('uid', 'pages', '('.$this->getPageIdClause($pageIds).')', '', '', '', 'uid');
+			if (count($rows) > 0) {
+				$pageIds = array_keys($rows);
+				$pageIdsString = implode(',', $pageIds);
+				
+				$pages[$level] = $pageIdsString;
+			} else {
+				break;
+			}
+		}
+		
+		return $pages;
+	}
+	
+	/**
+	 * Manipulate a record before using it to render the selector; may be used to replace a MM-relation etc.
+	 *
+	 * @param  array $row
+	 */
+	protected function manipulateRecord(&$row) {
+	}
+	
+	/**
+	 * Select the recrods from the table (uses the statement prepared in $this->selectClause)
+	 *
+	 * @return  resource  The resource which holds the records
+	 */
+	protected function selectRecords() {
+		global $TYPO3_DB;
+		
+		$result = $TYPO3_DB->exec_SELECTquery('*', $this->table, $this->selectClause, '', '', $this->start.', 50');
+		
+		if (!$result) {
+			$result = false;
+		}
+		
+		return $result;
+	}
+	
+	protected function checkRecordAccess($row, $uid) {
+		global $BE_USER;
+		
+		$retValue = true;
+		if (($this->mmForeignTable ? $this->mmForeignTable : $this->table) == 'pages') {
+			$row = t3lib_BEfunc::readPageAccess($uid, $BE_USER->getPagePermsClause(1));
+			if (!$row) 
+				$retValue = false;
+		} else {
+			$parent = t3lib_BEfunc::readPageAccess($row['pid'], $BE_USER->getPagePermsClause(1));
+			if (!is_array($parent))
+				$retValue = false;
+		}
+		
+		return $retValue;
+	}
+	
+	/**
+	 * Overlay the given record with its workspace-version, if any
+	 * 
+	 * @return  void
+	 */
+	protected function makeWorkspaceOverlay(&$row) {
+		global $BE_USER;
+		
+			// check for workspace-versions 
+		if ($BE_USER->workspace != 0 && $this->tableConfig['ctrl']['versioningWS'] == true) {
+			t3lib_BEfunc::workspaceOL(($this->mmForeignTable ? $this->mmForeignTable : $this->table), $row);
+		}
+	}
+	
+	/**
+	 * Return the icon for a record - just a wrapper for two functions from t3lib_iconWorks
+	 *
+	 * @param  array  $row The record to get the icon for
+	 * @return string The path to the icon
+	 */
+	protected function getIcon($row) {
+		$icon = t3lib_iconWorks::getIcon(($this->mmForeignTable ? $this->mmForeignTable : $this->table), $row);
+		$icon = t3lib_iconWorks::skinImg('', $icon, '', 1);
+		
+		return $icon;
+	}
+	
+	/**
+	 * Returns the path for a record. Is the whole path for all records except pages - for these the last part is cut 
+	 * off, because it contains the pagetitle itself, which would be double information
+	 * 
+	 * The path is returned uncut, cutting has to be done by calling function. 
+	 *
+	 * @param  array   $row The row
+	 * @param  integer $uid The records uid
+	 * @return string  The record-path
+	 */
+	protected function getRecordPath(&$row, $uid) {
+		global $BE_USER;
+		
+		if ($this->config['titleSegmentLimit']) {
+			$titleLimit = $this->config['titleSegmentLimit'];
+		} else {
+			$titleLimit = 0;
+		}
+		
+		if (($this->mmForeignTable ? $this->mmForeignTable : $this->table) == 'pages') {
+			$path = t3lib_BEfunc::getRecordPath($uid, '', $titleLimit);
+			
+				// for pages we only want the first (n-1) parts of the path, because the n-th part is the page itself
+			$path = substr($path, 0, strrpos($path, '/', -2)).'/';
+		} else {
+			$path = t3lib_BEfunc::getRecordPath($row['pid'], '', $titleLimit);
+		}
+		
+		return $path;
+	}
+	
+	/**
+	 * Returns a label for a given record; usually only a wrapper for t3lib_BEfunc::getRecordTitle
+	 *
+	 * @param  array $row
+	 * @return The label for the record
+	 */
+	protected function getLabel($row) {
+		$label = t3lib_BEfunc::getRecordTitle(($this->mmForeignTable ? $this->mmForeignTable : $this->table), $row);
+		if ($label !== '') {
+			$label =  t3lib_div::fixed_lgd_cs($label, 20);
+		} else {
+			$label = '<em>'.$this->getLL('l_no_title').'</em>';
+		}
+		
+		return $label;
+	}
+	
+	/**
+	 * Calls a user function for rendering the page.
+	 * 
+	 * This user function should manipulate $entry, especially $entry['text']
+	 *
+	 * @param  array $row   The row
+	 * @param  array $entry The entry to render
+	 * @return array The rendered entry (will be put into a <li> later on
+	 */
+	protected function renderRecord($row, $entry) {
+			// call renderlet if available (normal pages etc. usually don't have one)
+		$func = $this->config['renderFunc'];
+		if ($func != '') {
+			$params = array('table' => $this->table, 'uid' => $row['uid'], 'row' => $row, 'entry' => &$entry);
+			t3lib_div::callUserFunction($func, $params, $this, '');
+		}
+		
+		return $entry;
+	}
+
+	/**
+	 * Returns language label from locallang_core.php
+	 * Labels must be prefixed with either "l_" or "m_".
+	 * The prefix "l_" maps to the prefix "labels." inside locallang_core.php
+	 * The prefix "m_" maps to the prefix "mess." inside locallang_core.php
+	 *
+	 * @param	string		The label key
+	 * @return	string		The value of the label, fetched for the current backend language.
+	 */
+	function getLL($str)	{
+		$content = '';
+
+		switch(substr($str,0,2))	{
+			case 'l_':
+				$content = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.'.substr($str,2));
+			break;
+			case 'm_':
+				$content = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:mess.'.substr($str,2));
+			break;
+		}
+		return $content;
+	}
+	
+	/**
+	 * Returns a string as to use a replacement for IN (...) in an SQL where-clause. Needed for compatibility with
+	 * MSSQL
+	 * 
+	 * @param  array  $pageIds The pages to use for the clause
+	 * @return string
+	 */
+	private function getPageIdClause($pageIds) {
+		$pageArr = array();
+		foreach ($pageIds as $pageId) {
+			$pageArr[] = 'pid='.$pageId;
+		}
+		
+		return implode(' OR ', $pageArr);
+	}
+}
Index: typo3/gfx/group_suggest.gif
===================================================================
Kann nicht anzeigen: Dateityp ist als binär angegeben.
svn:mime-type = application/octet-stream

Eigenschaftsänderungen: typo3/gfx/group_suggest.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Index: typo3/stylesheet.css
===================================================================
--- typo3/stylesheet.css	(Revision 157)
+++ typo3/stylesheet.css	(Revision 159)
@@ -646,6 +646,46 @@
 
 
 
+DIV.suggest_choices {
+	position:absolute;
+	width:300px;
+	background-color:white;
+	border:1px solid #888;
+	margin:0px;
+	padding:0px;
+}
+DIV.suggest_choices UL {
+	list-style-type:none;
+	margin:0px;
+	padding:0px;
+}
+DIV.suggest_choices LI.selected { background-color: #ffb !important;}
+DIV.suggest_choices LI {
+	list-style-type:none;
+	display:block;
+	margin:0;
+	padding:2px;
+	padding-left:24px;	
+	height:32px;
+	cursor:pointer;
+	background-color:#EFEFF4;
+	background-repeat:no-repeat;
+	background-position:4px center;
+}
+DIV.suggest_choices LI.pages {
+	background-color:#FCC;	
+}
+DIV.suggest_choices SPAN.label {
+	font-weight:bold;
+}
+DIV.suggest_choices SPAN.uid {
+	font-size:0.9em;
+	margin-left:0.3em;
+}
+DIV.suggest_choices SPAN.path {
+	font-size:0.9em;
+	margin-top:0.3em;
+}
 
 
 
