Dateien TYPO3core_orig_cvs/t3lib/.class.t3lib_formmail.php.marks und TYPO3core_testing/t3lib/.class.t3lib_formmail.php.marks sind verschieden.
diff -ruN TYPO3core_orig_cvs/t3lib/class.t3lib_tcemain.php TYPO3core_testing/t3lib/class.t3lib_tcemain.php
--- TYPO3core_orig_cvs/t3lib/class.t3lib_tcemain.php	2006-01-17 16:32:34.000000000 +0100
+++ TYPO3core_testing/t3lib/class.t3lib_tcemain.php	2006-01-18 21:28:12.000000000 +0100
@@ -2070,7 +2070,7 @@
 			$modifyAccessList = $this->checkModifyAccessList($table);
 			if (!$modifyAccessList)	{
 				$this->log($table,$id,2,0,1,"Attempt to modify table '%s' without permission",1,array($table));
-			}
+			}	// FIXME: $id not set here (Comment added by Sebastian Kurfuerst)

 				// Check basic permissions and circumstances:
 			if (isset($TCA[$table]) && !$this->tableReadOnly($table) && is_array($this->cmdmap[$table]) && $modifyAccessList)	{
@@ -2135,6 +2135,9 @@
 							case 'delete':
 								$this->deleteAction($table, $id);
 							break;
+							case 'undelete':
+								$this->undeleteRecord($table, $id);
+							break;
 						}

 						foreach($hookObjectsArr as $hookObj) {
@@ -3008,7 +3011,18 @@
 	}

 	/**
-	 * Deleting a record
+	 * Undelete a record
+	 *
+	 * @param	string		Table name
+	 * @param	integer		Record UID
+	 * @return	void
+	 */
+	function undeleteRecord($table,$uid)	{
+		$this->deleteRecord($table,$uid,TRUE,FALSE,TRUE);
+	}
+
+	/**
+	 * Deleting/Undeleting a record
 	 * This function may not be used to delete pages-records unless the underlying records are already deleted
 	 * Deletes a record regardless of versioning state (live of offline, doesn't matter, the uid decides)
 	 * If both $noRecordCheck and $forceHardDelete are set it could even delete a "deleted"-flagged record!
@@ -3017,9 +3031,10 @@
 	 * @param	integer		Record UID
 	 * @param	boolean		Flag: If $noRecordCheck is set, then the function does not check permission to delete record
 	 * @param	boolean		If TRUE, the "deleted" flag is ignored if applicable for record and the record is deleted COMPLETELY!
+	 * @param	boolean		If TRUE, the "deleted" flag is set to 0 again and thus, the item is undeleted.
 	 * @return	void
 	 */
-	function deleteRecord($table,$uid, $noRecordCheck=FALSE, $forceHardDelete=FALSE)	{
+	function deleteRecord($table,$uid, $noRecordCheck=FALSE, $forceHardDelete=FALSE,$undeleteRecord=FALSE)	{
 		global $TCA;

 		$uid = intval($uid);
@@ -3029,8 +3044,9 @@

 				$deleteRow = $TCA[$table]['ctrl']['delete'];
 				if ($deleteRow && !$forceHardDelete)	{
+					$value = $undeleteRecord ? 0 : 1;
 					$updateFields = array(
-						$deleteRow => 1
+						$deleteRow => $value
 					);

 					if ($TCA[$table]['ctrl']['tstamp']) {
@@ -3038,7 +3054,7 @@
 					}

 						// If the table is sorted, then the sorting number is set very high
-					if ($TCA[$table]['ctrl']['sortby'])	{
+					if ($TCA[$table]['ctrl']['sortby'] && !$undeleteRecord)	{
 						$updateFields[$TCA[$table]['ctrl']['sortby']] = 1000000000;
 					}

@@ -3062,10 +3078,11 @@
 					$GLOBALS['TYPO3_DB']->exec_DELETEquery($table, 'uid='.intval($uid));
 				}

+				$state = $undeleteRecord ? 1 : 3;
 				if (!$GLOBALS['TYPO3_DB']->sql_error())	{
-					$this->log($table,$uid,3,0,0,'');
+					$this->log($table,$uid,$state,0,0,'');
 				} else {
-					$this->log($table,$uid,3,0,100,$GLOBALS['TYPO3_DB']->sql_error());
+					$this->log($table,$uid,$state,0,100,$GLOBALS['TYPO3_DB']->sql_error());
 				}

 					// Update reference index:
@@ -4398,55 +4415,36 @@
 			$TSConfig = $this->getTCEMAIN_TSconfig($tscPID);

 			$tE = $this->getTableEntries($table,$TSConfig);
-			$keepEntries = strcmp($tE['history.']['keepEntries'],'') ? t3lib_div::intInRange($tE['history.']['keepEntries'],0,200) : 10;
-			$maxAgeSeconds = 60*60*24*(strcmp($tE['history.']['maxAgeDays'],'') ? t3lib_div::intInRange($tE['history.']['maxAgeDays'],0,200) : 7);	// one week
+			$maxAgeSeconds = 60*60*24*(strcmp($tE['history.']['maxAgeDays'],'') ? t3lib_div::intInRange($tE['history.']['maxAgeDays'],0,365) : 30);	// one month

 				// Garbage collect old entries:
-			$this->clearHistory($table,$id,t3lib_div::intInRange($keepEntries-1,0),$maxAgeSeconds);
+			$this->clearHistory($maxAgeSeconds, $table);

 				// Set history data:
-			if ($keepEntries)	{
-				$fields_values = array();
-				$fields_values['history_data'] = serialize($this->historyRecords[$table.':'.$id]);
-				$fields_values['fieldlist'] = implode(',',array_keys($this->historyRecords[$table.':'.$id]['newRecord']));
-				$fields_values['tstamp'] = time();
-				$fields_values['tablename'] = $table;
-				$fields_values['recuid'] = $id;
-				$fields_values['sys_log_uid'] = $logId;
+			$fields_values = array();
+			$fields_values['history_data'] = serialize($this->historyRecords[$table.':'.$id]);
+			$fields_values['fieldlist'] = implode(',',array_keys($this->historyRecords[$table.':'.$id]['newRecord']));
+			$fields_values['tstamp'] = time();
+			$fields_values['tablename'] = $table;
+			$fields_values['recuid'] = $id;
+			$fields_values['sys_log_uid'] = $logId;
+
+			$GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_history', $fields_values);

-				$GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_history', $fields_values);
-			}
 		}
 	}

 	/**
 	 * Clearing sys_history table from older entries that are expired.
-	 * All snapshots are excluded of course.
 	 *
-	 * @param	string		Table name
-	 * @param	integer		Record UID
-	 * @param	integer		$keepEntries (int+) defines the number of current entries from sys_history table to keep in addition to the new one which is put in.
 	 * @param	integer		$maxAgeSeconds (int+) however will set a max age in seconds so that any entry older than current time minus the age removed no matter what. If zero, this is not effective.
+	 * @param	string		table where the history should be cleared
 	 * @return	void
 	 */
-	function clearHistory($table,$id,$keepEntries=10,$maxAgeSeconds=604800)		{
+	function clearHistory($maxAgeSeconds=604800,$table)	{
 		$tstampLimit = $maxAgeSeconds ? time()-$maxAgeSeconds : 0;

-		$where = '
-			tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table, 'sys_history').'
-			AND recuid='.intval($id).'
-			AND snapshot=0';
-
-		$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,tstamp', 'sys_history', $where, '', 'uid DESC', intval($keepEntries).',1');
-		$resRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
-		if ($tstampLimit && intval($resRow['tstamp'])<$tstampLimit)	{
-			$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,tstamp', 'sys_history', $where.' AND tstamp<'.intval($tstampLimit), '', 'uid DESC', '1');
-			$resRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
-
-			$GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_history', $where.' AND uid<='.intval($resRow['uid']));
-		} elseif (is_array($resRow)) {
-			$GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_history', $where.' AND uid<='.intval($resRow['uid']));
-		}
+		$GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_history', 'tstamp<'.intval($tstampLimit).' AND tablename="'.$table.'"');
 	}

 	/**
diff -ruN TYPO3core_orig_cvs/typo3/alt_clickmenu.php TYPO3core_testing/typo3/alt_clickmenu.php
--- TYPO3core_orig_cvs/typo3/alt_clickmenu.php	2006-01-17 16:32:37.000000000 +0100
+++ TYPO3core_testing/typo3/alt_clickmenu.php	2006-01-18 21:26:00.000000000 +0100
@@ -303,6 +303,10 @@
 				$menuItems['spacer2']='spacer';
 				$menuItems['delete']=$this->DB_delete($table,$uid,$elInfo);
 			}
+
+			if(!in_array('history',$this->disabledItems))	{
+				$menuItems['history']=$this->DB_history($table,$uid,$elInfo);
+			}
 		}

 			// Adding external elements to the menuItems array
diff -ruN TYPO3core_orig_cvs/typo3/class.show_rechis.inc TYPO3core_testing/typo3/class.show_rechis.inc
--- TYPO3core_orig_cvs/typo3/class.show_rechis.inc	2005-11-02 23:51:52.000000000 +0100
+++ TYPO3core_testing/typo3/class.show_rechis.inc	2006-01-18 21:26:00.000000000 +0100
@@ -28,91 +28,49 @@
  * Class for the record history display script (show_rechis.php)
  *
  * $Id: class.show_rechis.inc,v 1.17 2005/11/02 22:51:52 typo3 Exp $
- * Revised for TYPO3 3.6 November/2003 by Kasper Skaarhoj
  * XHTML Compliant
  *
- * @author	Kasper Skaarhoj <kasperYYYY@typo3.com>
+ * @author	Sebastian Kurfuerst <sebastian@garbage-group.de>
  */
-/**
- * [CLASS/FUNCTION INDEX of SCRIPT]
- *
- *
- *
- *   83: class recordHistory
- *  106:     function recordHistory()
- *  124:     function main()
- *  155:     function displaySysHistoryEntry($sh_uid)
- *  219:     function revertToPreviousValues($element,$field)
- *  285:     function saveState($element,$sumUp)
- *  339:     function displayHistory($element)
- *
- *              SECTION: Various helper functions
- *  540:     function nextHisUid($element,$hisUid)
- *  586:     function compareChangesWithCurrent($element,$changeRec)
- *  631:     function readFieldTypes($table,$id)
- *  662:     function cmp($changeStatus,$oldRecord)
- *  685:     function removeFilefields($table,$dataArray)
- *  708:     function renderEntry($entry,$table)
- *  769:     function listHeader()
- *  813:     function linkPage($str,$inparams=array(),$anchor='')
- *  841:     function getChangesSinceRecord($element,$hisUid=0,$hisUid_Stop=0)
- *
- * TOTAL FUNCTIONS: 15
- * (This index is automatically created/updated by the extension "extdeveval")
- *
- */
-
-
-
-
-
-
-
-
-
-


 /**
  * Class for the record history display script (show_rechis.php)
  *
- * @author	Kasper Skaarhoj <kasperYYYY@typo3.com>
+ * @author	Sebastian Kurfuerst <sebastian@garbage-group.de>
  * @package TYPO3
  * @subpackage core
  */
-class recordHistory {

+class recordHistory {
 		// External, static:
 	var $maxSteps=20;		// Maximum number of sys_history steps to show.
+	var $showDiff=1;		// display diff or not (0-no diff, 1-inline, 2-popup)
+	// TODO: $displayDiff=2
+	var $showSubElements=1;		// on a pages table - show sub elements as well.
+	var $showInsertDelete=1;		// show inserts and deletes as well

-		// Internal, dynamic:
-	var $listType = 0;		// This value determines the kind of list build. The variable is used as a parameter from some functions.
-
-		// Internal, static. GPvars:
-	var $sh_uid;			// sh_uid is the id-number of the sys_history log item to SHOW
+		// Internal, GPvars
 	var $element;			// Element reference, syntax [tablename]:[uid]
-	var $saveState;			// Saving states: Points to a sys_history UID which should be saved.
-	var $returnUrl;			// Return URL - kept in links, used to link back to calling module.
-	var $revert;			// String identifying mode of reverting: Either all fields or only a single field to revert. See function revertToPreviousValues()
-	var $sumUp;			// Generally used as a pointer to a sys_history uid as a state.
-	var $doReturn;			// If set, function revertToPreviousValues() will perform a redirect to returnUrl
-
+	var $lastSyslogId;		// syslog ID which is not shown anymore
+	var $returnUrl;

+		// Internal
+	var $changeLog;
+	var $showMarked=FALSE;
 	/**
 	 * Constructor for the class
 	 *
 	 * @return	void
 	 */
 	function recordHistory()	{
-
 			// GPvars:
-		$this->sh_uid = t3lib_div::_GP('sh_uid');
 		$this->element = t3lib_div::_GP('element');
-		$this->saveState = t3lib_div::_GP('saveState');
 		$this->returnUrl = t3lib_div::_GP('returnUrl');
-		$this->revert = t3lib_div::_GP('revert');
-		$this->sumUp = t3lib_div::_GP('sumUp');
-		$this->doReturn = t3lib_div::_GP('doReturn');
+		$this->lastSyslogId = t3lib_div::_GP('diff');
+		$this->rollbackFields = t3lib_div::_GP('rollbackFields');
+			// resolve sh_uid if set
+		$this->resolveShUid();
 	}

 	/**
@@ -122,685 +80,687 @@
 	 * @return	void
 	 */
 	function main()	{
+		$content = '';

-		$content='';
-
-			// If link from sys log:
-			// sh_uid is the id-number of the sys_history log item
-		if ($this->sh_uid)	{
-			$content.=$this->displaySysHistoryEntry($this->sh_uid);
+			// save snapshot
+		if (t3lib_div::_GP('highlight') && !t3lib_div::_GP('settings'))	{
+			$this->toggleHighlight(t3lib_div::_GP('highlight'));
 		}

-			// If link to element:
-		if ($this->element)	{
-			$this->resolveElement();
-			if ($this->revert && $this->sumUp)	{
-				$content.=$this->revertToPreviousValues($this->element,$this->revert);
+		$content .= $this->displaySettings();
+		if ($this->createChangeLog())	{
+			if ($this->rollbackFields)	{
+				$completeDiff = $this->createMultipleDiff();
+				$this->performRollback($completeDiff);
+
+			}
+			if ($this->lastSyslogId)	{
+				$completeDiff = $this->createMultipleDiff();
+				$content .= $this->displayMultipleDiff($completeDiff);
 			}
-			if ($this->saveState)	{
-				$content.=$this->saveState($this->element,$this->saveState);
+			if ($this->element)	{
+				$content .= $this->displayHistory();
 			}
-			$content.=$this->displayHistory($this->element);
 		}
-
-			// Return content variable:
 		return $content;
 	}

+	/*******************************
+	 *
+	 * database actions
+	 *
+	 *******************************/
+
 	/**
-	 * Displays a specific entry from the sys_history table
+	 * toggles highlight state of record
 	 *
-	 * @param	integer		UID of sys_history table entry
-	 * @return	string		HTML content
+	 * @param	integer		uid of sys_history entry
 	 */
-	function displaySysHistoryEntry($sh_uid)	{
-		global $SOBE, $LANG, $TCA;
-
-			// Select the entry from the table:
- 		$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_history', 'uid='.intval($sh_uid));
-		$newRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
-
-			// If an entry was found:
-		if (is_array($newRow))	{
-
-				// Init:
-			$this->listType=0;
-			$lines=array();
-
-				// Create header:
-			$recIdentString = $LANG->sL($TCA[$newRow['tablename']]['ctrl']['title']).'/'.$newRow['recuid'];
-			$recIdentString = $this->linkPage(htmlspecialchars($recIdentString),array('sh_uid'=>'','element'=>$newRow['tablename'].':'.$newRow['recuid']),'uid_'.$sh_uid);
-			$theTime = t3lib_BEfunc::datetime($newRow['tstamp']).', '.t3lib_BEfunc::calcAge(time()-$newRow['tstamp'],$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears'));
-			$lines[]='
-				<tr class="bgColor5">
-					<td colspan="4">
-						<strong>'.$LANG->getLL('tableUid',1).':</strong> '.$recIdentString.'<br />
-						<strong>'.$LANG->getLL('time',1).':</strong> '.htmlspecialchars($theTime).'<br />
-					</td>
-				</tr>';
-
-				// Add header to accumulation:
-			$lines[]=$this->listHeader();
-
-				// Get the entry data and add it:
-			$historyData = unserialize($newRow['history_data']);
-			$lines = array_merge($lines,$this->renderEntry($historyData,$newRow['tablename']));
-
-				// Combine all content into a table for layout:
-			$theCode='
-
-				<!--
-					History for item:
-				-->
-				<table border="0" cellpadding="2" cellspacing="2" id="typo3-history-item">
-					'.implode('',$lines).'
-				</table>';
-
-			$theCode.='
-				<br /><img'.t3lib_iconWorks::skinImg('','gfx/icon_note.gif','width="18" height="16"').' align="top" alt="" />'.$LANG->getLL('differenceMsg').'<br /><br />';
-
-				// Add CSH:
-			$theCode.= t3lib_BEfunc::cshItem('xMOD_csh_corebe', 'history_entry', $GLOBALS['BACK_PATH'],'');
-
-				// Create the module section:
-			$content.=$SOBE->doc->section($LANG->getLL('changes'),$theCode,0,1);
+	function toggleHighlight($uid)	{
+		$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('snapshot','sys_history','uid='.intval($uid));
+		$tmp = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
+		if ($tmp['snapshot'])	{
+			$tmp = 0;
+		} else {
+			$tmp = 1;
 		}
-
-			// Return content:
-		return $content;
+		$updateFields = array('snapshot' => $tmp);
+		$GLOBALS['TYPO3_DB']->exec_UPDATEquery('sys_history','uid='.intval($uid),$updateFields);
 	}

 	/**
-	 * Return to previous values for element
+	 * perform rollback
 	 *
-	 * @param	string		Element reference, syntax "[table]:[uid]"
-	 * @param	string		Tells which field to restore. A single field (eg named "myField") is defined as "field:myField" while ALL fields is indicated by the string "ALL_FIELDS"
-	 * @return	void		The function writes through tceMain and ends with a header-location, if instructed to.
-	 */
-	function revertToPreviousValues($element,$field)	{
-		$sumUp = $this->sumUp;	// sys_history uid from which to get previous values
-
-		$elParts = explode(':',$element);
-		$redirect = intval($this->doReturn);
-		if ($sumUp==-1)	{	// Undo/Redo
-			$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-						'uid',
-						'sys_history',
-						'sys_history.tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($elParts[0], 'sys_history').'
-							AND sys_history.recuid='.intval($elParts[1]),
-						'',
-						'uid DESC',
-						'1'
-					);
-			if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))	{
-				$sumUp=$row['uid'];
-			}
-			$redirect = 1;
-		}
-		if ($sumUp!=-1)	{
-			$changeRec=$this->compareChangesWithCurrent($element,$this->getChangesSinceRecord($element,$sumUp));
-
-			$data =array();
-			if (t3lib_BEfunc::getRecord($elParts[0],$elParts[1]))	{
-
-					// Fields field(s) to restore:
-				if ($field=='ALL_FIELDS')	{
-					$data=$changeRec['oldRecord'];
-				} elseif(substr($field,0,6)=='field:') {
-					$data[substr($field,6)]=$changeRec['oldRecord'][substr($field,6)];
-				}
-					// Removing fields:
-				$data = $this->removeFilefields($elParts[0],$data);
-
-					// If there are fields to write:
-				if (count($data))	{
-
-						// Setting data right:
-					$inData=array();
-					$inData[$elParts[0]][$elParts[1]]=$data;
-
-						// Writes the data:
-					$tce = t3lib_div::makeInstance('t3lib_TCEmain');
-					$tce->stripslashes_values=0;
-					$tce->debug=0;
-					$tce->dontProcessTransformations=1;
-					$tce->start($inData,array());
-					$tce->process_datamap();
+	 * @param	array		diff array to rollback
+	 * @return	void
+	 * @access	private
+	 */
+	function performRollback($diff)	{
+		if (!$this->rollbackFields)	{
+			return 0;
+		}
+			// PROCESS INSERTS AND DELETES
+			// rewrite inserts and deletes
+		$cmdmapArray = array();
+		if ($diff['insertsDeletes'])	{
+			foreach ($diff['insertsDeletes'] as $key => $action)	{
+				$elParts = explode(':',$key);
+				if ($action == 1)	{	// inserted records should be deleted
+					$cmdmapArray[$elParts[0]][$elParts[1]]['delete'] = 1;
+						// when the record is deleted, the contents of the record do not need to be updated
+					unset($diff['oldData'][$key]);
+					unset($diff['newData'][$key]);
+				} else {	// deleted records should be inserted again
+					$cmdmapArray[$elParts[0]][$elParts[1]]['undelete'] = 1;
 				}
 			}
 		}
-
-		if ($redirect)	{
-			Header ('Location: '.t3lib_div::locationHeaderUrl($this->returnUrl));
-			exit;
-		}
+			// Writes the data:
+		if ($cmdmapArray)	{
+			$tce = t3lib_div::makeInstance('t3lib_TCEmain');
+			$tce->stripslashes_values=0;
+			$tce->debug=0;
+			$tce->dontProcessTransformations=1;
+			$tce->start(array(),$cmdmapArray);
+			$tce->process_cmdmap();
+			unset($tce);
+		}
+
+			// PROCESS CHANGES
+			// create an array for process_datamap
+		$diff_modified = array();
+		foreach ($diff['oldData'] as $key => $value)	{
+			$splitKey = explode(':',$key);
+			$diff_modified[$splitKey[0]][$splitKey[1]] = $value;
+		}
+
+		$rollbackData = explode(':',$this->rollbackFields);
+
+		switch (count($rollbackData))	{
+			case 1:	// TODO: implement all tables / one table
+				$data = $diff_modified;
+				break;
+			case 2:	// one record
+				$data[$rollbackData[0]][$rollbackData[1]] = $diff_modified[$rollbackData[0]][$rollbackData[1]];
+				break;
+			case 3:	// one field in one record
+				$data[$rollbackData[0]][$rollbackData[1]][$rollbackData[2]] = $diff_modified[$rollbackData[0]][$rollbackData[1]][$rollbackData[2]];
+				break;
+		}
+			// Removing fields:
+		$data = $this->removeFilefields($rollbackData[0],$data);
+
+			// Writes the data:
+		$tce = t3lib_div::makeInstance('t3lib_TCEmain');
+		$tce->stripslashes_values=0;
+		$tce->debug=0;
+		$tce->dontProcessTransformations=1;
+		$tce->start($data,array());
+		$tce->process_datamap();
+		unset($tce);
+
+			// return to normal operation
+		$this->lastSyslogId = FALSE;
+		$this->rollbackFields = FALSE;
+		$this->createChangeLog();
 	}

+	/*******************************
+	 *
+	 * Display functions
+	 *
+	 *******************************/
+
 	/**
-	 * Will save state uid $sumUp of element
+	 * Displays settings
 	 *
-	 * @param	string		Element reference, syntax "[table]:[uid]"
-	 * @param	integer		sys_history uid from which to get previous values
-	 * @return	void
+	 * @return	string		HTML code to modify settings
 	 */
-	function saveState($element,$sumUp)	{
-		$elParts = explode(':',$element);
-
-			// Find the changes since $sumUp sys_history uid
-		$changeRec = $this->getChangesSinceRecord($element,$sumUp);
-
-			// Select most recent sys_history record for the element:
-		$lastestData = array();
-		$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-					'history_data',
-					'sys_history',
-					'sys_history.tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($elParts[0], 'sys_history').'
-						AND sys_history.recuid='.intval($elParts[1]),
-					'',
-					'uid DESC',
-					'1'
-				);
-		if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))	{
-			$lastestData = unserialize($row['history_data']);
-		}
-
-			// Create forged history data from the most recent state and the previous state to save:
-		$historyRecords=array();
-		$historyRecords['oldRecord'] = $changeRec['changes'];
-		$historyRecords['newRecord'] = array();
-
-		reset($historyRecords['oldRecord']);
-		while(list($kk)=each($historyRecords['oldRecord']))	{
-			$historyRecords['newRecord'][$kk]=$lastestData['newRecord'][$kk];
-		}
-
-			// Update log:
-		$updateID = $GLOBALS['BE_USER']->writelog(3,0,0,0,'Saved state in sys_history','');
-
-			// Create query for inserting into sys_history table:
-		$fields_values = array(
-			'history_data' => serialize($historyRecords),
-			'fieldlist' => implode(',',array_keys($historyRecords['oldRecord'])),
-			'tstamp' => time(),
-			'tablename' => $elParts[0],
-			'recuid' => $elParts[1],
-			'sys_log_uid' => $updateID,
-			'snapshot' => 1
+	function displaySettings()	{
+			// TODO: remove "show sub elements" when just one record is selected and no page
+		global $BE_USER, $LANG, $SOBE;
+			// get current selection from UC, merge data, write it back to UC
+		$currentSelection = is_array($BE_USER->uc['moduleData']['history']) ? $BE_USER->uc['moduleData']['history'] : array('maxSteps' => '', 'showDiff' => 1, 'showSubElements' => 1, 'showInsertDelete' => 1);
+
+		$currentSelectionOverride = t3lib_div::_GP('settings');
+		if ($currentSelectionOverride)	{
+			$currentSelection = array_merge($currentSelection,$currentSelectionOverride);
+			$BE_USER->uc['moduleData']['history'] = $currentSelection;
+			$BE_USER->writeUC($BE_USER->uc);
+		}
+
+			// display selector for number of history entries
+		$selector['maxSteps'] = array(
+			10 => 10,
+			20 => 20,
+			50 => 50,
+			100 => 100,
+			'' => 'maxSteps_all',
+			'marked' => 'maxSteps_marked'
+		);
+		$selector['showDiff'] = array(
+			0 => 'showDiff_no',
+			1 => 'showDiff_inline'
+		);
+		$selector['showSubElements'] = array(
+			0 => 'no',
+			1 => 'yes',
+		);
+		$selector['showInsertDelete'] = array(
+			0 => 'no',
+			1 => 'yes',
 		);
-			// Save state by executing this query:
-		$GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_history', $fields_values);
+			// render selectors
+		$displayCode = '';
+		foreach ($selector as $key => $values)	{
+			$displayCode .= '<tr><td>'.$LANG->getLL($key,1).'</td><td><select name="settings['.$key.']" onChange="document.settings.submit()" style="width:100px">';
+			foreach ($values as $singleKey => $singleVal) {
+				$caption = $LANG->getLL($singleVal,1)?$LANG->getLL($singleVal,1):$singleVal;
+				$displayCode .= '<option value="'.$singleKey.'" '.(($singleKey ==  $currentSelection[$key])?'selected':'').'> '.$caption.'</option>';
+			}
+			$displayCode .= '</select></td></tr>';
+		}
+			// set values correctly
+		if ($currentSelection['maxSteps'] != 'marked')	{
+			$this->maxSteps = $currentSelection['maxSteps']?intval($currentSelection['maxSteps']):'';
+		} else {
+			$this->showMarked = TRUE;
+			$this->maxSteps = FALSE;
+		}
+		$this->showDiff = intval($currentSelection['showDiff']);
+		$this->showSubElements = intval($currentSelection['showSubElements']);
+		$this->showInsertDelete = intval($currentSelection['showInsertDelete']);
+
+		$content = '';
+			// get link to page history if the element history is shown
+		$elParts = explode(':',$this->element);
+		if ($elParts[0] != 'pages')	{
+			$content .= '<b>'.$LANG->getLL('elementHistory',1).'</b><br />';
+			$pid = t3lib_BEfunc::getRecordRaw($elParts[0],'uid='.intval($elParts[1]));
+			$content .= $this->linkPage($LANG->getLL('elementHistory_link',1),array('element' => 'pages:'.$pid['pid']));
+		}
+		$content .= '<form name="settings" action="'.t3lib_div::getIndpEnv('TYPO3_REQUEST_URL').'" method="post"><table>'.$displayCode.'</table></form>';
+		return $SOBE->doc->section($LANG->getLL('settings',1),$content,0,1,0,0);
+
 	}

 	/**
-	 * Displays the history states of an element
+	 * Shows the full change log
 	 *
-	 * @param	string		Element reference, syntax "[table]:[uid]"
 	 * @return	string		HTML for list, wrapped in a table.
 	 */
-	function displayHistory($element)	{
-		global $SOBE, $LANG, $TCA;
-
-			// Initialize:
-		$elParts = explode(':',$element);
-		$table = $elParts[0];
-
-			// If table is found in $TCA:
-		if ($TCA[$table])	{
-
-				// Counting number of states:
-			$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-						'COUNT(*)',
-						'sys_history,sys_log',
-						'sys_history.sys_log_uid=sys_log.uid
-							AND sys_history.tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table, 'sys_history').'
-							AND sys_history.recuid='.intval($elParts[1])
-					);
-			list($Rcount) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
-
-				// Selecting the $this->maxSteps most recent states:
-			$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-						'sys_history.*,sys_log.userid',
-						'sys_history,sys_log',
-						'sys_history.sys_log_uid=sys_log.uid
-							AND sys_history.tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table, 'sys_history').'
-							AND sys_history.recuid='.intval($elParts[1]),
-						'',
-						'sys_log.uid',
-						t3lib_div::intInRange($Rcount-$this->maxSteps,0).','.$this->maxSteps
-					);
+	function displayHistory()	{
+		global $LANG;
+		global $SOBE;
+		global $TCA;

-				// Traversing the result, building up changesArray / changeLog:
-			$changesArray=array();
-			$changeLog=array();
-			while ($newRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))	{
-				$hisDat = unserialize($newRow['history_data']);
-				if (is_array($hisDat['newRecord']) && is_array($hisDat['oldRecord']))	{
-						// If intermedia changes:
-					$intermediaChanges = $this->cmp($changesArray,$hisDat['oldRecord']);
-					if (count($intermediaChanges) && !$newRow['snapshot'])	{
-						$changeLog[]=$intermediaChanges;
-					}
+		$lines=array();

-						// Add hisDat to the changeLog
-					$hisDat['uid']=$newRow['uid'];
-					$hisDat['tstamp']=$newRow['tstamp'];
-					$hisDat['user']=$newRow['userid'];
-					$hisDat['snapshot']=$newRow['snapshot'];
-					$changeLog[]=$hisDat;
+			// Initialize:
+		$lines[] = '<tr class="bgColor5 c-head">
+				<td> </td>
+				<td>'.$LANG->getLL('time',1).'</td>
+				<td>'.$LANG->getLL('age',1).'</td>
+				<td>'.$LANG->getLL('user',1).'</td>
+				<td>'.$LANG->getLL('tableUid',1).'</td>
+				<td>'.$LANG->getLL('differences',1).'</td>
+				<td>&nbsp;</td>
+			</tr>';
+
+			// get default page TSconfig expiration time
+		$elParts = explode(':',$this->element);
+		if ($elParts[0] != 'pages')	{
+			$tmp = t3lib_BEfunc::getRecordRaw($elParts[0],'uid='.intval($elParts[1]));
+			$pid = $tmp['pid'];
+		} else {
+			$pid = $elParts[1];
+		}
+		$tmpTsConfig = $GLOBALS['BE_USER']->getTSConfig('TCEMAIN',t3lib_BEfunc::getPagesTSconfig($pid));
+		$expirationTime = isset($tmpTsConfig['properties']['default.']['history.']['maxAgeDays']) ? $tmpTsConfig['properties']['default.']['history.']['maxAgeDays'] : 30;
+
+		$expirationTimestamp = $expirationTime ? (time() - 60*60*24*$expirationTime) : 0;
+		$expirationWarning = 0;
+
+			// TODO: Maybe user/groupname blinding necessary
+		#$be_group_Array=t3lib_BEfunc::getListGroupNames('title,uid');
+		#$groupArray=array_keys($be_group_Array);
+
+		$be_user_array = t3lib_BEfunc::getUserNames();
+		#if (!$GLOBALS['BE_USER']->isAdmin())		$be_user_Array = t3lib_BEfunc::blindUserNames($be_user_Array,$groupArray,1);
+
+			// Traverse changelog array:
+		if (!$this->changeLog)	{
+			return 0;
+		}
+		$i = 0;
+		foreach ($this->changeLog as $sysLogUid => $entry)	{
+				// stop after maxSteps
+			if ($i > $this->maxSteps && $this->maxSteps)	{
+				break;
+			}
+
+				// display inconsistency warning
+			if ($entry['tstamp'] < $expirationTimestamp && !$expirationWarning)	{
+				$expirationWarning = 1;
+
+				$lines[] = '
+				<tr class="bgColor4-20">
+					<td colspan="7"><b>'.$LANG->getLL('consistenceWarning',1).'</b></td>
+				</tr>';
+			}

-						// Update change array
-						// This is used to detect if any intermedia changes has been made.
-					$changesArray = array_merge($changesArray,$hisDat['newRecord']);
+				// show only marked states
+			if (!$entry['snapshot'] && $this->showMarked)	{
+				continue;
+			}
+			$i++;
+				// get user names
+			$userName = ($entry['user']?$be_user_array[$entry['user']]['username']:$LANG->getLL('externalChange',1));
+
+				// build up single line
+			$singleLine = array();
+
+				// diff link
+			$image = '<img'.t3lib_iconWorks::skinImg('','gfx/button_top_right.gif').' align="top" alt="'.$LANG->getLL('sumUpChanges',1).'" title="'.$LANG->getLL('sumUpChanges',1).'" />';
+			$singleLine[] = '<span>'.$this->linkPage($image,array('diff' => $sysLogUid)).'</span>';	// remove first link
+
+			$singleLine[] = htmlspecialchars(t3lib_BEfunc::datetime($entry['tstamp']));	// add time
+			$singleLine[] = htmlspecialchars(t3lib_BEfunc::calcAge(time()-$entry['tstamp'],$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears')));	// add age
+			$singleLine[] = htmlspecialchars($userName);	// add user name
+			$singleLine[] = $this->linkPage($this->generateTitle($entry['tablename'],$entry['recuid']),array('element' => $entry['tablename'].':'.$entry['recuid']),'',$LANG->getLL('linkRecordHistory',1));	// add record UID
+
+				// show insert/delete/diff/changed field names
+			if ($entry['action'])	{	// insert or delete of element
+				$singleLine[] = '<strong>'.htmlspecialchars($LANG->getLL($entry['action'],1)).'</strong>';
+			} else {
+				if (!$this->showDiff)	{	// display field names instead of full diff
+					// re-write field names with labels
+				$tmpFieldList = explode(',',$entry['fieldlist']);
+				foreach ($tmpFieldList as $key => $value)	{
+					$tmp = str_replace(':','',$LANG->sl(t3lib_BEfunc::getItemLabel($entry['tablename'],$value),1));
+					if($tmp)	$tmpFieldList[$key] = $tmp;
+					else	unset($tmpFieldList[$key]);	// remove fields if no label available
+				}
+				$singleLine[] = htmlspecialchars(implode(',',$tmpFieldList));
+				} else {	// display diff
+					$diff = $this->renderDiff($entry,$entry['tablename']);
+					$singleLine[] = $diff;
+				}
+			}
+				// show link to mark/unmark state
+			if (!$entry['action'])	{
+				if ($entry['snapshot'])	{
+					$image = '<img'.t3lib_iconWorks::skinImg('','gfx/unmarkstate.gif').' align="top" alt="'.$LANG->getLL('unmarkState',1).'" title="'.$LANG->getLL('unmarkState',1).'" />';
 				} else {
-					debug('ERROR: [displayHistory]');
+					$image = '<img'.t3lib_iconWorks::skinImg('','gfx/markstate.gif').' align="top" alt="'.$LANG->getLL('markState',1).'" title="'.$LANG->getLL('markState',1).'" />';
 				}
+				$singleLine[] = $this->linkPage($image,array('highlight' => $entry['uid']));
+			} else {
+				$singleLine[] = '';
 			}

+			$bgColorClass = $entry['snapshot'] ? 'bgColor2' : 'bgColor4-20';
+				// put line together
+			$lines[] = '
+				<tr class="'.$bgColorClass.'">
+					<td>'.implode('</td><td>',$singleLine).'</td>
+				</tr>';
+		}

-			$lines=array();
-			$darkerBgColor_interM = '#cccccc';
-			if ($this->sumUp)	{	// Show details for a single point in the list:
+			// Finally, put it all together:
+		$theCode = '
+			<!--
+				History (list):
+			-->
+			<table border="0" cellpadding="2" cellspacing="2" id="typo3-history">
+				'.implode('',$lines).'
+			</table>';

-					// Initialize:
-				$changeLog=array();		// array is reset here because we want to show only one item (and therefore we will build it all over again...)
-				$changeLog[]=$this->compareChangesWithCurrent($element,$this->getChangesSinceRecord($element,$this->sumUp));
-				$this->listType=2;
-				$lines[]=$this->listHeader();
-				$be_users = t3lib_BEfunc::getUserNames();
+		if ($this->lastSyslogId)	{
+			$theCode .= '<br />' .  $this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/group_tobottom.gif').' alt="'.$LANG->getLL('fullView',1).'" title="'.$LANG->getLL('fullView',1).'" />',array('diff' => ''));
+		}
+			// Add message about the difference view.
+		$theCode .= '<br /><img'.t3lib_iconWorks::skinImg('','gfx/icon_note.gif','width="18" height="16"').' align="top" alt="" />'.$LANG->getLL('differenceMsg').'<br /><br />';

-					// Get the previous/next uids:
-				list($prevHisUid,$nextHisUid) = $this->nextHisUid($element,$this->sumUp);
+			// Add CSH:
+			// TODO: FIX CSH
+		$theCode .= t3lib_BEfunc::cshItem('xMOD_csh_corebe', 'history_'.($this->sumUp ? 'sum' : 'log'), $GLOBALS['BACK_PATH'],'');

-					// Create the set of navigation links:
-				$linkPack =
-					($prevHisUid ? $this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/pilup.gif','width="14" height="14"').' title="'.$LANG->getLL('prev',1).'" alt="" />', array('sumUp'=>$prevHisUid)) : '').	// previous
-					($nextHisUid ? $this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/pildown.gif','width="14" height="14"').' title="'.$LANG->getLL('next',1).'" alt="" />', array('sumUp'=>$nextHisUid)) : '').	// next
-					'<br />'.$this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/history2.gif','width="13" height="12"').' title="'.$LANG->getLL('historyList',1).'" alt="" />', array('sumUp'=>''), 'uid_'.$this->sumUp).	// back to list
-					$this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/savesnapshot.gif','width="17" height="12"').' title="'.$LANG->getLL('saveState',1).'" alt="" />', array('saveState'=>$this->sumUp,'sumUp'=>''), 'latest');	// save state
+			// Add the whole content as a module section:
+		return $SOBE->doc->section($LANG->getLL('changes'),$theCode,0,1);
+	}

-					// Traverse changelog array:
-				foreach($changeLog as $entry)	{
+	/**
+	 * Displays a diff over multiple fields including rollback links
+	 *
+	 * @param	array		difference array
+	 * @return	string		HTML output
+	 */
+	function displayMultipleDiff($diff)	{
+		global $SOBE, $LANG;
+		$content = '';

-						// Set user-names:
-					if (!is_array($entry['userList']))	$entry['userList']=array();
-					foreach($entry['userList'] as $uLk => $uV)	{
-						$entry['userList'][$uLk]=$be_users[$uV]['username'];
-					}
+			// get all array keys needed
+		$arrayKeys = array_merge(array_keys($diff['newData']),array_keys($diff['insertsDeletes']),array_keys($diff['oldData']));
+		$arrayKeys = array_unique($arrayKeys);
+
+		foreach ($arrayKeys as $key)	{
+			$record = '';
+			$elParts = explode(':',$key);
+				// turn around diff because it should be a "rollback preview"
+			if ($diff['insertsDeletes'][$key] == 1)	{	// insert
+				$record .= '<b>'.$LANG->getLL('delete',1).'</b>';
+				$record .= '<br />';
+			} elseif ($diff['insertsDeletes'][$key] == -1)	{
+				$record .= '<b>'.$LANG->getLL('insert',1).'</b>';
+				$record .= '<br />';
+			}
+				// build up temporary diff array
+				// turn around diff because it should be a "rollback preview"
+			if ($diff['newData'][$key])	{
+				$tmpArr['newRecord'] = $diff['oldData'][$key];
+				$tmpArr['oldRecord'] = $diff['newData'][$key];
+				$record .= $this->renderDiff($tmpArr, $elParts[0],$elParts[1]);
+			}
+
+			$elParts = explode(':',$key);
+			$titleLine = $this->createRollbackLink($key, $LANG->getLL('revertRecord',1),1) . $this->generateTitle($elParts[0],$elParts[1]);
+			$record = '<div style="margin-left:10px;padding-left:5px;border-left:1px solid black;border-bottom:1px dotted black;padding-bottom:2px;">'.$record.'</div>';

-						// Add the header:
-					$theTime = t3lib_BEfunc::datetime($entry['tstamp']).', '.t3lib_BEfunc::calcAge(time()-$entry['tstamp'],$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears'));
-					$lines[]='
-						<tr class="bgColor4-20">
-							<td valign="top">'.$linkPack.'</td>
-							<td colspan="4"><b>'.$LANG->getLL('time',1).':</b> '.htmlspecialchars($theTime).' &nbsp; - &nbsp; <b>'.$LANG->getLL('changeCount',1).':</b> '.$entry['counter'].'<br />
-								<b>'.$LANG->getLL('users',1).':</b> '.implode(', ',$entry['userList']).'
-							</td>
-						</tr>';
+			$content .= $SOBE->doc->section($titleLine,$record,0,0,0,1);
+		}
+		$content = $this->createRollbackLink('ALL', $LANG->getLL('revertAll',1),0)  . '<div style="margin-left:10px;padding-left:5px;border-left:1px solid black;border-bottom:1px dotted black;padding-bottom:2px;">'.$content.'</div>';

-						// Add content:
-					if (isset($entry['oldRecord']) && isset($entry['newRecord']))	{	// If there ARE differences to show, then add lines for each changed field:
-						$lines = array_merge($lines,$this->renderEntry($entry,$table));
-					} else {	// Otherwise, if no changes - show a message about that!
-						$lines[]='
-							<tr class="bgColor4">
-								<td colspan="5" align="center"><br /><b>'.$LANG->getLL('similar',1).'</b><br /><br /></td>
-							</tr>';
-					}
-				}
-			} else {	// Show the full change Log:
+		return $SOBE->doc->section($LANG->getLL('mergedDifferences',1),$content,0,1,0,1);
+	}
+
+	/**
+	 * Renders HTML table-rows with the comparison information of an sys_history entry record
+	 *
+	 * @param	array		sys_history entry record.
+	 * @param	string		The table name
+	 * @param	integer		If set to UID of record, display rollback links
+	 * @return	string		HTML table
+	 * @access private
+	 */
+	function renderDiff($entry,$table,$rollbackUid=0)	{
+		global $SOBE, $LANG, $TCA;
+		$lines=array();
+ 		if (is_array($entry['newRecord']))	{

-					// Initialize:
-				$this->listType=1;
-				$be_users = t3lib_BEfunc::getUserNames();
-				$lines[]=$this->listHeader();
+			$t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff');

-					// Traverse changelog array:
-				foreach($changeLog as $c => $entry)	{
+			$fieldsToDisplay = array_keys($entry['newRecord']);
+			foreach($fieldsToDisplay as $fN)	{
+				t3lib_div::loadTCA($table);
+				if (is_array($TCA[$table]['columns'][$fN]) && $TCA[$table]['columns'][$fN]['config']['type']!='passthrough')	{

-						// Add spacer line:
+						// Create diff-result:
+					$diffres = $t3lib_diff_Obj->makeDiffDisplay(
+						t3lib_BEfunc::getProcessedValue($table,$fN,$entry['oldRecord'][$fN],0,1),
+						t3lib_BEfunc::getProcessedValue($table,$fN,$entry['newRecord'][$fN],0,1)
+					);
 					$lines[]='
-						<tr>
-							<td colspan="3">&nbsp;</td>
+						<tr class="bgColor4">
+						'.($rollbackUid?'<td style="width:33px">'.$this->createRollbackLink($table.':'.$rollbackUid.':'.$fN, $LANG->getLL('revertField',1),2).'</td>':'').'
+							<td style="width:90px"><em>'.$LANG->sl(t3lib_BEfunc::getItemLabel($table,$fN),1).'</em></td>
+							<td style="width:300px">'.nl2br($diffres).'</td>
 						</tr>';
-
-						// Anchor to latest entry:
-					$lastAnchor = ($c+1==count($changeLog)?'<a name="latest"></a>':'');
-
-						// Render state header:
-					if ($entry['uid'])	{	// This state was made by the backend:
-						$theTime = $this->linkPage(t3lib_BEfunc::datetime($entry['tstamp']),array('sh_uid'=>$entry['uid'],'element'=>''));
-						$theAge = ', '.t3lib_BEfunc::calcAge(time()-$entry['tstamp'],$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears'));
-						$bgColorClass = $entry['snapshot'] ? 'bgColor2' : 'bgColor4-20';
-						$lines[]='
-							<tr class="'.$bgColorClass.'">
-								<td colspan="2">'.
-									$lastAnchor.
-									'<a name="uid_'.$entry['uid'].'"></a>'.
-									($entry['snapshot'] ? '<img'.t3lib_iconWorks::skinImg('','gfx/snapshot.gif','width="12" height="12"').' alt="" />':'').
-									'<b>'.$LANG->getLL('time',1).':</b> '.$theTime.htmlspecialchars($theAge).' &nbsp; - &nbsp; <b>'.$LANG->getLL('user',1).':</b> '.$be_users[$entry['user']]['username'].
-								'</td>
-								<td>'.
-									$this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/history.gif','width="13" height="12"').' title="'.$LANG->getLL('revertAllFields',1).'" alt="" />', array('revert'=>'ALL_FIELDS','sumUp'=>$entry['uid'],'doReturn'=>1)).
-									$this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/history_details.gif','width="12" height="12"').' title="'.$LANG->getLL('sumUpChanges',1).'" alt="" />', array('sumUp'=>$entry['uid'])).
-								'</td>
-							</tr>';
-					} else {	// This state must have been some external change:
-						$lines[]='
-							<tr bgcolor="'.$darkerBgColor_interM.'">
-								<td colspan="3"><strong>'.$LANG->getLL('externalChange',1).'</strong></td>
-							</tr>';
-					}
-						// Merge state header with all entries in the state:
-					$lines = array_merge($lines,$this->renderEntry($entry,$table));
 				}
 			}
-
-				// Finally, put it all together:
-			$theCode='
-
-				<!--
-					Item history (either list or single):
-				-->
-				<table border="0" cellpadding="2" cellspacing="2" id="typo3-history">
+		}
+		if ($lines)	{
+			$content = '<table border="0" cellpadding="2" cellspacing="2" id="typo3-history-item">
 					'.implode('',$lines).'
 				</table>';
-
-				// Add message about the difference view.
-			$theCode.= '<br /><img'.t3lib_iconWorks::skinImg('','gfx/icon_note.gif','width="18" height="16"').' align="top" alt="" />'.$LANG->getLL('differenceMsg').'<br /><br />';
-
-				// Add CSH:
-			$theCode.= t3lib_BEfunc::cshItem('xMOD_csh_corebe', 'history_'.($this->sumUp ? 'sum' : 'log'), $GLOBALS['BACK_PATH'],'');
-
-				// Add the whole content as a module section:
-			return $SOBE->doc->section($LANG->getLL('changes'),$theCode,0,1);
+			return $content;
 		}
+		return NULL;	// error fallback
 	}

-
-
-
-
-
-
-
-
 	/*******************************
 	 *
-	 * Various helper functions
+	 * build up history
 	 *
 	 *******************************/

 	/**
-	 * Based on the uid of a sys_history record (a state) this method will find the uids of the previous and next state (if any)
+	 * Creates a diff between the current version of the records and the selected version
 	 *
-	 * @param	string		Element reference, syntax "[table]:[uid]"
-	 * @param	integer		Current state uid
-	 * @return	array		Array with previous and next uid as key 0 / 1
-	 * @access private
+	 * @return	array		diff for many elements
 	 */
-	function nextHisUid($element,$hisUid)	{
-		$elParts = explode(':',$element);
-
-			// Prev:
-		$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-					'uid',
-					'sys_history',
-					'tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($elParts[0], 'sys_history').'
-						AND recuid='.intval($elParts[1]).'
-						AND uid<'.intval($hisUid),
-					'',
-					'uid DESC',
-					'1'
-				);
-		if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))	{
-			$prevUid = $row['uid'];
-		}
-
-			// Next:
-		$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-					'uid',
-					'sys_history',
-					'tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($elParts[0], 'sys_history').'
-						AND recuid='.intval($elParts[1]).'
-						AND uid>'.intval($hisUid),
-					'',
-					'uid',
-					'1'
-				);
-		if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))	{
-			$nextUid = $row['uid'];
-		}
-
-			// Return next and previous ids:
-		return array($prevUid,$nextUid);
-	}
-
-	/**
-	 * This compares a certain sys_history state (given by the $changeRec array) with the current values of the element refered to by $element.
-	 *
-	 * @param	string		Element reference, syntax "[table]:[uid]"
-	 * @param	array		Array with the state information from a certain state. This kind of array is produced by getChangesSinceRecord()
-	 * @return	array		Array with the changes registered in.
-	 * @access private
-	 * @see getChangesSinceRecord()
-	 */
-	function compareChangesWithCurrent($element,$changeRec)	{
-		global $TCA;
-
-			// Initialize:
-		$sumChangesArray=array();
-		$elParts = explode(':',$element);
-		$newChangeRec=array();
-
-			// If tablename is found in $TCA:
-		if ($TCA[$elParts[0]])	{
-
-				// Select current record content of element:
-			$currentRecord = t3lib_BEfunc::getRecord($elParts[0],$elParts[1]);
-
-				// If that is found and the "changes" entry of the $changeRec is an array, then proceed:
-			if (is_array($currentRecord) && is_array($changeRec['changes']))	{
-
-					// For each entry in "changes" we compare the field content with the current and if there is a difference, it is tracked in the array $newChangeRec
-				foreach($changeRec['changes'] as $fN => $fV)	{
-					if (strcmp($fV,$currentRecord[$fN]))	{
-						$newChangeRec['oldRecord'][$fN]=$fV;
-						$newChangeRec['newRecord'][$fN]=$currentRecord[$fN];
+	function createMultipleDiff()	{
+		$insertsDeletes = array();
+		$newArr = array();
+		$differences = array();
+		if (!$this->changeLog)	{
+			return 0;
+		}
+
+			// traverse changelog array
+		$i = 0;
+		$total = count($this->changeLog);
+		foreach ($this->changeLog as $key => $value)	{
+			$i++;
+			$field = $value['tablename'].':'.$value['recuid'];
+				// inserts / deletes
+			if ($value['action'])	{
+				if($i < $total)	{	// don't revert the last log entry
+					if (!$insertsDeletes[$field])	{
+						$insertsDeletes[$field] = 0;
+					}
+					if ($value['action'] == 'insert')	{
+						$insertsDeletes[$field]++;
+					} else {
+						$insertsDeletes[$field]--;
+					}
+						// unset not needed fields
+					if ($insertsDeletes[$field] == 0)	{
+						unset($insertsDeletes[$field]);
 					}
 				}
-					// Finally, setting some general information fields:
-				$newChangeRec['tstamp']=min($changeRec['tstamp']);
-				$newChangeRec['counter']=$changeRec['counter'];
-				$newChangeRec['userList']=array_unique($changeRec['userList']);
 			} else {
-				return false;	// No arrays, possibly no record
+					// update fields
+				if (!isset($newArr[$field]) && $i < $total)	{	// first row of field, not the last row
+					$newArr[$field] = $value['newRecord'];
+					$differences[$field] = array_merge($differences[$field],$value['oldRecord']);
+				} elseif (isset($newArr[$field]) && $i < $total) { // standard
+					$differences[$field] = array_merge($differences[$field],$value['oldRecord']);
+				} elseif (!isset($newArr[$field]) && $i == $total) {	// last row
+				} elseif (isset($newArr[$field]) && $i == $total) {	// last row
+					$differences[$field] = array_merge($differences[$field],$value['newRecord']);
+				}
 			}
 		}

-			// Returns the array of changes detected:
-		return $newChangeRec;
-	}
-
-	/**
-	 * Returns the record of $table/$id along with the sql field types for each field
-	 *
-	 * @param	string		The table name
-	 * @param	integer		The uid of the record
-	 * @return	array		An array with two num keys; in 0 is the current record, in 1 is the field types for each field.
-	 * @access private
-	 */
-	function readFieldTypes($table,$id)	{
-
-			// Select record:
-		$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, 'uid='.intval($id));
-
-			// Fetch the types of the fields.
-		if ($GLOBALS['TYPO3_DB']->sql_num_rows($res))	{
-			$currentRecord = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
-			$c=0;
-			$cRecTypes=array();
-			foreach($currentRecord as $col => $val)	{
-				//$cRecTypes[$col] = $GLOBALS['TYPO3_DB']->sql_field_type($table,$col);
-// DBAL
-				$cRecTypes[$col] = $GLOBALS['TYPO3_DB']->sql_field_type($res,$c);
-				$c++;
+			// remove entries where there were no changes effectively
+		foreach ($newArr as $record => $value)	{
+			foreach ($value as $key => $innerVal)	{
+				if ($newArr[$record][$key] == $differences[$record][$key])	{
+					unset($newArr[$record][$key]);
+					unset($differences[$record][$key]);
+				}
 			}
-		}
-
-		$GLOBALS['TYPO3_DB']->sql_free_result($res);

-		return array($currentRecord,$cRecTypes);
+		}
+		return array(
+			'newData' => $newArr,
+			'oldData' => $differences,
+			'insertsDeletes' => $insertsDeletes
+		);
 	}

 	/**
-	 * Compares the old record with the changed fields.
+	 * Creates change log including sub-elements, filling $this->changeLog
 	 *
-	 * @param	array		Record with field/value pairs (what has changed)
-	 * @param	array		Record with field/value pairs
-	 * @return	array		Comparison result.
-	 * @access private
 	 */
-	function cmp($changeStatus,$oldRecord)	{
+	function createChangeLog()	{

-			// Initialize:
-		$changes=array();
+		global $TCA;
+		$elParts = explode(':',$this->element);
+		$changeLog = $this->getHistoryData($elParts[0],$elParts[1]);

-			// Traverse $oldRecord
-		foreach($oldRecord as $fN => $fV)	{
-			if (isset($changeStatus[$fN]) && strcmp($fV,$changeStatus[$fN]))	{
-				$changes['oldRecord'][$fN]=$changeStatus[$fN];
-				$changes['newRecord'][$fN]=$fV;
+			// get history of tables of this page and merge it into changelog
+		if ($elParts[0] == 'pages' && $this->showSubElements)	{
+			foreach ($TCA as $tablename => $value)	{
+				$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid',$tablename,'pid='.intval($elParts[1]));	// check if there are records on the page
+				while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))	{
+					if ($newChangeLog = $this->getHistoryData($tablename, $row['uid']))	{	// if there is history data available, merge it into changelog
+						foreach ($newChangeLog as $key => $value)	{
+							$changeLog[$key] = $value;
+						}
+					}
+				}
 			}
 		}
-		return $changes;
+		if(!$changeLog)	{
+			return 0;
+		}
+
+		krsort($changeLog);
+		$this->changeLog = $changeLog;
+
+		return 1;
 	}

 	/**
-	 * Will traverse the field names in $dataArray and look in $TCA if the fields are of types which cannot be handled by the sys_history (that is currently group types with internal_type set to "file")
+	 * Gets history and delete/insert data from sys_log and sys_history
 	 *
-	 * @param	string		Table name
-	 * @param	array		The data array
-	 * @return	array		The modified data array
-	 * @access private
+	 * @param	string		DB table name
+	 * @param	integer		UID of record
+	 * @return	array		history data of the record
 	 */
-	function removeFilefields($table,$dataArray)	{
+	function getHistoryData($table,$uid)	{
 		global $TCA;
-
+		$uid = $this->resolveElement($table,$uid);
+			// If table is found in $TCA:
 		if ($TCA[$table])	{
-			t3lib_div::loadTCA($table);
+				// Selecting the $this->maxSteps most recent states:
+			$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+						'sys_history.*,sys_log.userid',
+						'sys_history,sys_log',
+						'sys_history.sys_log_uid=sys_log.uid
+							AND sys_history.tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table, 'sys_history').'
+							AND sys_history.recuid='.intval($uid),
+						'',
+						'sys_log.uid DESC',
+						$this->maxSteps
+					);

-			foreach($TCA[$table]['columns'] as $field => $config)	{
-				if ($config['config']['type']=='group' && $config['config']['internal_type']=='file')	{
-					unset($dataArray[$field]);
+				// Traversing the result, building up changesArray / changeLog:
+			#$changesArray=array();	// used temporarily to track intermedia changes
+			$changeLog=array();
+			while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))	{
+					// only history until a certain syslog ID needed
+				if ($row['sys_log_uid'] < $this->lastSyslogId && $this->lastSyslogId)	{
+					continue;
 				}
-			}
-		}
-		return $dataArray;
-	}
-
-	/**
-	 * Renders HTML table-rows with the comparison information of an sys_history entry record
-	 *
-	 * @param	array		sys_history entry record.
-	 * @param	string		The table name
-	 * @return	array		HTML table rows in an array
-	 * @access private
-	 */
-	function renderEntry($entry,$table)	{
-		global $SOBE, $LANG, $TCA;
+				$hisDat = unserialize($row['history_data']);
+				if (is_array($hisDat['newRecord']) && is_array($hisDat['oldRecord']))	{

-		$lines=array();
- 		if (is_array($entry['newRecord']))	{
+						// If intermedia changes:
+					#$intermediaChanges = $this->cmp($changesArray,$hisDat['newRecord']);
+					#if (count($intermediaChanges))	{	//  && !$row['snapshot']
+						//$changeLog[]=$intermediaChanges;
+						// FIXME: ARRAY INDEX MIGHT HAVE AN ERROR!!!!!
+					#}

-			$t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff');
+						// Add hisDat to the changeLog
+						// TODO: Possible to overload it with $row?
+					$hisDat['uid']=$row['uid'];
+					$hisDat['tstamp']=$row['tstamp'];
+					$hisDat['user']=$row['userid'];
+					$hisDat['snapshot']=$row['snapshot'];
+					$hisDat['fieldlist']=$row['fieldlist'];
+					$hisDat['tablename']=$row['tablename'];
+					$hisDat['recuid']=$row['recuid'];

-			$fieldsToDisplay = array_keys($entry['newRecord']);
-			foreach($fieldsToDisplay as $fN)	{
-				t3lib_div::loadTCA($table);
-				if (is_array($TCA[$table]['columns'][$fN]) && $TCA[$table]['columns'][$fN]['config']['type']!='passthrough')	{
+					$changeLog[$row['sys_log_uid']]=$hisDat;

-						// Create diff-result:
-					$diffres = $t3lib_diff_Obj->makeDiffDisplay(
-						t3lib_BEfunc::getProcessedValue($table,$fN,$entry['oldRecord'][$fN],0,1),
-						t3lib_BEfunc::getProcessedValue($table,$fN,$entry['newRecord'][$fN],0,1)
+						// Update change array
+						// This is used to detect if any intermedia changes have been made.
+					#$changesArray = array_merge($changesArray,$hisDat['oldRecord']);
+				} else {
+					debug('ERROR: [getHistoryData]');
+					return 0;	// error fallback
+				}
+			}
+				// SELECT INSERTS/DELETES
+			if ($this->showInsertDelete)	{
+					// Select most recent inserts and deletes // WITHOUT snapshots
+				$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+						'uid,userid,action,tstamp',
+						'sys_log',
+						'type=1
+							AND ( action=1 OR action=3 )
+							AND tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table, 'sys_log').'
+							AND recuid='.intval($uid),
+						'',
+						'uid DESC',
+						$this->maxSteps
 					);
+				while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))	{
+
+					if ($row['uid'] < $this->lastSyslogId && $this->lastSyslogId)	{
+						continue;
+					}
+					$hisDat = array();

-						// Depending on list type, we make the row:
-					switch($this->listType)	{
-						case 1:
-							$lines[]='
-								<tr class="bgColor4">
-									<td><em>'.$LANG->sl(t3lib_BEfunc::getItemLabel($table,$fN),1).'</em></td>
-									<td>'.nl2br($diffres).'</td>
-									<td>&nbsp;</td>
-								</tr>';
-						break;
-						case 2:
-							$lines[]='
-								<tr class="bgColor4">
-									<td><em>'.$LANG->sl(t3lib_BEfunc::getItemLabel($table,$fN)).'</em></td>
-									<td>'.htmlspecialchars(t3lib_BEfunc::getProcessedValue($table,$fN,$entry['oldRecord'][$fN])).'</td>
-									<td>'.$this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/history.gif','width="13" height="12"').' title="'.$LANG->getLL('revertField',1).'" alt="" />', array('revert'=>'field:'.$fN)).'</td>
-									<td>'.htmlspecialchars(t3lib_BEfunc::getProcessedValue($table,$fN,$entry['newRecord'][$fN])).'</td>
-									<td>'.nl2br($diffres).'</td>
-								</tr>';
-						break;
-						default:
-							$lines[]='
-								<tr class="bgColor4">
-									<td><em>'.$LANG->sl(t3lib_BEfunc::getItemLabel($table,$fN)).'</em></td>
-									<td>'.htmlspecialchars(t3lib_BEfunc::getProcessedValue($table,$fN,$entry['oldRecord'][$fN])).'</td>
-									<td>'.htmlspecialchars(t3lib_BEfunc::getProcessedValue($table,$fN,$entry['newRecord'][$fN])).'</td>
-									<td>'.nl2br($diffres).'</td>
-								</tr>';
-						break;
+					switch ($row['action'])	{
+						case 1:	// Insert
+							$hisDat['action'] = 'insert';
+							break;
+						case 3:	// Delete
+							$hisDat['action'] = 'delete';
+							break;
 					}
+					$hisDat['tstamp']=$row['tstamp'];
+					$hisDat['user']=$row['userid'];
+					$hisDat['tablename'] = $table;
+					$hisDat['recuid'] = $uid;
+					$changeLog[$row['uid']] = $hisDat;
 				}
 			}
+			return $changeLog;
 		}
-		return $lines;
+		return 0;	// error fallback
 	}

-	/**
-	 * Creates a header row based on the value of $this->listType
+
+	/*******************************
 	 *
-	 * @return	string		HTML table header row
-	 * @access private
+	 * Various helper functions
+	 *
+	 *******************************/
+
+	/**
+	 * generates the title and puts the record title behind
 	 */
-	function listHeader()	{
-		global $SOBE, $LANG;
+	function generateTitle($table, $uid)	{
+		global $TCA;

-		switch($this->listType)	{
-			case 1:
-				$out='
-					<tr class="bgColor5 c-head">
-						<td>'.$LANG->getLL('fieldName',1).':</td>
-						<td>'.$LANG->getLL('difference',1).':</td>
-						<td>&nbsp;</td>
-					</tr>';
-			break;
-			case 2:
-				$out='
-					<tr class="bgColor5 c-head">
-						<td>'.$LANG->getLL('fieldName',1).':</td>
-						<td>'.$LANG->getLL('oldValue',1).':</td>
-						<td>'.$this->linkPage('<img'.t3lib_iconWorks::skinImg('','gfx/history.gif','width="13" height="12"').' title="'.$LANG->getLL('revertAllFields',1).'" alt="" />', array('revert'=>'ALL_FIELDS')).'</td>
-						<td>'.$LANG->getLL('currentValue',1).':</td>
-						<td>'.$LANG->getLL('difference',1).':</td>
-					</tr>';
-			break;
-			default:
-				$out='
-					<tr class="bgColor5 c-head">
-						<td>'.$LANG->getLL('fieldName',1).':</td>
-						<td>'.$LANG->getLL('oldValue',1).':</td>
-						<td>'.$LANG->getLL('newValue',1).':</td>
-						<td>'.$LANG->getLL('difference',1).':</td>
-					</tr>';
-			break;
+		$out = $table.':'.$uid;
+		if ($labelField = $TCA[$table]['ctrl']['label'])	{
+			$record = t3lib_BEfunc::getRecordRaw($table, 'uid='.intval($uid));
+			if (strlen(trim($record[$labelField])))	{
+				$out .= ' ('.htmlspecialchars($record[$labelField]).')';
+			}
 		}
 		return $out;
 	}
+	/**
+	 * creates a link for the rollback
+	 *
+	 * @param	sting		parameter which is set to rollbackFields
+	 * @param	string		optional, alternative label and title tag of image
+	 * @param	integer		optional, type of rollback: 0 - ALL; 1 - element; 2 - field
+	 * @return	string		HTML output
+	 */
+	function createRollbackLink($key, $alt='', $type=0)	{
+		 global $LANG;
+
+		 return $this->linkPage('<img '.t3lib_iconWorks::skinImg('','gfx/revert_'.$type.'.gif','width="33" height="33"').' alt="'.$alt.'" title="'.$alt.'" align="middle" />',array('rollbackFields'=>$key));
+	 }

 	/**
 	 * Creates a link to the same page.
@@ -808,98 +768,99 @@
 	 * @param	string		String to wrap in <a> tags (must be htmlspecialchars()'ed prior to calling function)
 	 * @param	array		Array of key/value pairs to override the default values with.
 	 * @param	string		Possible anchor value.
+	 * @param	string		Possible title.
 	 * @return	string		Link.
 	 * @access private
 	 */
-	function linkPage($str,$inparams=array(),$anchor='')	{
+	function linkPage($str,$inparams=array(),$anchor='',$title='')	{

 			// Setting default values based on GET parameters:
-		$params['sh_uid']=$this->sh_uid;
-		$params['sumUp']=$this->sumUp;
 		$params['element']=$this->element;
 		$params['returnUrl']=$this->returnUrl;
-
+		$params['diff']=$this->lastSyslogId;
 			// Mergin overriding values:
 		$params = array_merge($params,$inparams);

 			// Make the link:
 		$Ahref = 'show_rechis.php?'.t3lib_div::implodeArrayForUrl('',$params).($anchor?'#'.$anchor:'');
-		$link = '<a href="'.htmlspecialchars($Ahref).'">'.$str.'</a>';
+		$link = '<a href="'.htmlspecialchars($Ahref).'"'.($title?' title="'.$title.'"':'').'>'.$str.'</a>';

 			// Return link:
 		return $link;
 	}

 	/**
-	 * This creates an array with the sum of differences between two points in the sys_history
+	 * Will traverse the field names in $dataArray and look in $TCA if the fields are of types which cannot be handled by the sys_history (that is currently group types with internal_type set to "file")
 	 *
-	 * @param	string		Element reference, syntax "[table]:[uid]"
-	 * @param	integer		sys_history uid from which to start the selection process
-	 * @param	integer		optional sys_history uid at which to stop the selection (thus applying an upper limit)
-	 * @return	array		Array with difference information
+	 * @param	string		Table name
+	 * @param	array		The data array
+	 * @return	array		The modified data array
 	 * @access private
 	 */
-	function getChangesSinceRecord($element,$hisUid=0,$hisUid_Stop=0)	{
+	function removeFilefields($table,$dataArray)	{
 		global $TCA;

-			// Init:
-		$sumChangesArray=array();
-		$sumChangesArray['changes']=array();
-		$elParts = explode(':',$element);
-
-			// If there is a table by the requested name:
-		if ($TCA[$elParts[0]])	{
-			$times = array();
-
-				// Create query for selecting sys_history records in time interval:
-			$addWhere = ' AND sys_history.uid>='.$hisUid;
-			if ($hisUid_Stop)	$addWhere.= ' AND sys_history.uid<='.$hisUid_Stop;
-				// Make query:
-			$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-							'sys_history.*,sys_log.userid',
-							'sys_history,sys_log',
-							'sys_history.sys_log_uid=sys_log.uid
-								AND sys_history.tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($elParts[0], 'sys_history').'
-								AND sys_history.recuid='.intval($elParts[1]).$addWhere,
-							'',
-							'uid DESC'
-						);
-
-				// Travese results:
-			while ($newRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))	{
-				$hisDat = unserialize($newRow['history_data']);
-				if (is_array($hisDat['newRecord']) && is_array($hisDat['oldRecord']))	{
-					$sumChangesArray['changes']=array_merge($sumChangesArray['changes'],$hisDat['oldRecord']);
-					$sumChangesArray['counter']++;
-					$sumChangesArray['tstamp'][]=$newRow['tstamp'];
-					$sumChangesArray['userList'][]=$newRow['userid'];
-				} else {
-					debug('ERROR!');
+		if ($TCA[$table])	{
+			t3lib_div::loadTCA($table);
+
+			foreach($TCA[$table]['columns'] as $field => $config)	{
+				if ($config['config']['type']=='group' && $config['config']['internal_type']=='file')	{
+					unset($dataArray[$field]);
 				}
+			}
+		}
+		return $dataArray;
+	}
+
+	/**
+	 * Compares the old record with the changed fields.
+	 *
+	 * @param	array		Record with field/value pairs (what has changed)
+	 * @param	array		Record with field/value pairs
+	 * @return	array		Comparison result.
+	 * @access private
+	 */
+	function cmp($newRecord,$oldRecord)	{
+			// Initialize:
+		$changes=array();

+			// Traverse $oldRecord
+		foreach($oldRecord as $fN => $fV)	{
+			if (isset($newRecord[$fN]) && strcmp($fV,$newRecord[$fN]))	{
+				$changes['oldRecord'][$fN]=$newRecord[$fN];
+				$changes['newRecord'][$fN]=$fV;
 			}
 		}
-		return $sumChangesArray;
+		return $changes;
 	}

 	/**
 	 * Convert input element reference to workspace version if any.
 	 *
-	 * @return	void
+	 * @param	string		table of input element
+	 * @param	integer		UID of record
+	 * @return	integer		converted UID of record
 	 */
-	function resolveElement()	{
-		$parts = explode(':',$this->element);
-
-		if (isset($GLOBALS['TCA'][$parts[0]]))	{
-			if ($workspaceVersion = t3lib_BEfunc::getWorkspaceVersionOfRecord($GLOBALS['BE_USER']->workspace, $parts[0], $parts[1], 'uid'))	{
-				$parts[1] = $workspaceVersion['uid'];
-				$this->element = implode(':', $parts);
+	function resolveElement($table,$uid)	{
+		if (isset($GLOBALS['TCA'][$table]))	{
+			if ($workspaceVersion = t3lib_BEfunc::getWorkspaceVersionOfRecord($GLOBALS['BE_USER']->workspace, $table, $uid, 'uid'))	{
+				$uid = $workspaceVersion['uid'];
 			}
 		}
+		return $uid;
 	}
-}

-if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/class.show_rechis.inc'])	{
-	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/class.show_rechis.inc']);
+	/**
+	 * resolve sh_uid (used from log)
+	 */
+	function resolveShUid()	{
+		if (t3lib_div::_GP('sh_uid'))	{
+			$sh_uid = t3lib_div::_GP('sh_uid');
+			$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*','sys_history', 'uid='.intval($sh_uid));
+			$record = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
+			$this->element = $record['tablename'].':'.$record['recuid'];
+			$this->lastSyslogId = $record['sys_log_uid']-1;
+		}
+	}
 }
 ?>
\ Kein Zeilenumbruch am Dateiende.
diff -ruN TYPO3core_orig_cvs/typo3/show_rechis.php TYPO3core_testing/typo3/show_rechis.php
--- TYPO3core_orig_cvs/typo3/show_rechis.php	2005-04-14 14:33:31.000000000 +0200
+++ TYPO3core_testing/typo3/show_rechis.php	2006-01-18 21:26:00.000000000 +0100
@@ -108,13 +108,18 @@
 			// Start history object
 		$historyObj = t3lib_div::makeInstance('recordHistory');

+			// Return link:
+		if ($historyObj->returnUrl)	{
+			$this->content .= '<a href="'.htmlspecialchars($historyObj->returnUrl).'" class="typo3-goBack"><img'.t3lib_iconWorks::skinImg('','gfx/goback.gif','width="14" height="14"').' alt="" />'.$LANG->getLL('returnLink',1).'</a>';
+		}
+
 			// Get content:
-		$this->content.= $historyObj->main();
+		$this->content .= $historyObj->main();

 			// Return link:
 		if ($historyObj->returnUrl)	{
 			$link = '<a href="'.htmlspecialchars($historyObj->returnUrl).'" class="typo3-goBack"><img'.t3lib_iconWorks::skinImg('','gfx/goback.gif','width="14" height="14"').' alt="" />'.$LANG->getLL('returnLink',1).'</a>';
-			$this->content.= $this->doc->section($LANG->getLL('return'),$link,0,1);
+			$this->content .= $this->doc->section($LANG->getLL('return'),$link,0,1);
 		}
 	}

diff -ruN TYPO3core_orig_cvs/typo3/sysext/extra_page_cm_options/class.tx_extrapagecmoptions.php TYPO3core_testing/typo3/sysext/extra_page_cm_options/class.tx_extrapagecmoptions.php
--- TYPO3core_orig_cvs/typo3/sysext/extra_page_cm_options/class.tx_extrapagecmoptions.php	2005-11-24 00:51:39.000000000 +0100
+++ TYPO3core_testing/typo3/sysext/extra_page_cm_options/class.tx_extrapagecmoptions.php	2006-01-18 21:26:00.000000000 +0100
@@ -135,7 +135,6 @@
 			if ($backRef->editOK)	{	// If the page can be edited, then show this:
 				if (!in_array('move_wizard',$backRef->disabledItems) && ($table=='pages' || $table=='tt_content'))	$localItems['move_wizard']=$backRef->DB_moveWizard($table,$uid,$backRef->rec);
 				if (!in_array('new_wizard',$backRef->disabledItems) && ($table=='pages' || $table=='tt_content'))	$localItems['new_wizard']=$backRef->DB_newWizard($table,$uid,$backRef->rec);
-				if (!in_array('history',$backRef->disabledItems))	$localItems['history']=$backRef->DB_history($table,$uid);
 				if (!in_array('perms',$backRef->disabledItems) && $table=='pages' && $BE_USER->check('modules','web_perm'))	$localItems['perms']=$backRef->DB_perms($table,$uid,$backRef->rec);
 				if (!in_array('db_list',$backRef->disabledItems) && $BE_USER->check('modules','web_list'))	$localItems['db_list']=$backRef->DB_db_list($table,$uid,$backRef->rec);
 			}
diff -ruN TYPO3core_orig_cvs/typo3/sysext/lang/locallang_show_rechis.xml TYPO3core_testing/typo3/sysext/lang/locallang_show_rechis.xml
--- TYPO3core_orig_cvs/typo3/sysext/lang/locallang_show_rechis.xml	2005-05-04 17:08:00.000000000 +0200
+++ TYPO3core_testing/typo3/sysext/lang/locallang_show_rechis.xml	2006-01-18 21:26:00.000000000 +0100
@@ -12,29 +12,41 @@
 	<data type="array">
 		<languageKey index="default" type="array">
 			<label index="title">Show record history</label>
-			<label index="tableUid">Table/Uid</label>
 			<label index="time">Time</label>
+			<label index="age">Age</label>
 			<label index="user">User</label>
-			<label index="changeCount">Changes since time</label>
-			<label index="changes">Changes to the record</label>
+			<label index="tableUid">Table:uid</label>
+			<label index="differences">Differences</label>
+			<label index="changes">Changelog</label>
 			<label index="return">Return</label>
 			<label index="returnLink">Click here to go back</label>
-			<label index="revertField">Restore old value of this field</label>
-			<label index="revertAllFields">Restore old values of all fields below</label>
+			<label index="revertAll">Rollback all changes shown</label>
+			<label index="revertRecord">Rollback single record</label>
+			<label index="revertField">Rollback single field</label>
 			<label index="externalChange">Intermediate external change!</label>
-			<label index="sumUpChanges">Accumulate changes up to this point</label>
-			<label index="historyList">Show history list</label>
-			<label index="users">Users</label>
-			<label index="similar">This state is similar to the current values of the record!</label>
-			<label index="prev">Previous state</label>
-			<label index="next">Next state</label>
-			<label index="saveState">Protect this state from being erased</label>
-			<label index="fieldName">Fieldname</label>
-			<label index="oldValue">Old value</label>
-			<label index="newValue">New value</label>
-			<label index="currentValue">Current value</label>
+			<label index="sumUpChanges">Rollback (Preview)</label>
+			<label index="markState">mark this change</label>
+			<label index="unmarkState">unMark this change</label>
+			<label index="elementHistory">You are currently seeing the history for an element.</label>
+			<label index="elementHistory_link">Show the full page history!</label>
+			<label index="linkRecordHistory">Limit history to this record</label>
 			<label index="differenceMsg">In the Difference column the &lt;span class=&quot;diff-g&quot;&gt;green colored text&lt;/span&gt; are new changes and the &lt;span class=&quot;diff-r&quot;&gt;red colored text&lt;/span&gt; are the old values which were removed.</label>
-			<label index="difference">Difference</label>
+			<label index="fullView">Return to full view</label>
+			<label index="insert">insert</label>
+			<label index="delete">delete</label>
+			<label index="mergedDifferences">Preview for Rollback</label>
+			<label index="settings">Settings</label>
+			<label index="maxSteps">Show entries:</label>
+			<label index="maxSteps_all">ALL</label>
+			<label index="maxSteps_marked">marked</label>
+			<label index="showDiff">Show diff:</label>
+			<label index="showDiff_no">No</label>
+			<label index="showDiff_inline">Inline</label>
+			<label index="showSubElements">Show sub elements:</label>
+			<label index="no">No</label>
+			<label index="yes">Yes</label>
+			<label index="showInsertDelete">Show inserts/deletes of records:</label>
+			<label index="consistenceWarning">From this point on, there is no guarantee that a rollback reverts all changes, as changes of records  prior to this message are normally not preserved.</label>
 		</languageKey>
 		<languageKey index="dk">EXT:csh_dk/lang/dk.locallang_show_rechis.xml</languageKey>
 		<languageKey index="de">EXT:csh_de/lang/de.locallang_show_rechis.xml</languageKey>
