TYPO3 API  SVNRelease
index.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) 2004-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
00006 *  All rights reserved
00007 *
00008 *  This script is part of the TYPO3 project. The TYPO3 project is
00009 *  free software; you can redistribute it and/or modify
00010 *  it under the terms of the GNU General Public License as published by
00011 *  the Free Software Foundation; either version 2 of the License, or
00012 *  (at your option) any later version.
00013 *
00014 *  The GNU General Public License can be found at
00015 *  http://www.gnu.org/copyleft/gpl.html.
00016 *
00017 *  This script is distributed in the hope that it will be useful,
00018 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 *  GNU General Public License for more details.
00021 *
00022 *  This copyright notice MUST APPEAR in all copies of the script!
00023 ***************************************************************/
00024 /**
00025  * Versioning module
00026  *
00027  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00028  */
00029 /**
00030  * [CLASS/FUNCTION INDEX of SCRIPT]
00031  *
00032  *
00033  *
00034  *  102: class tx_version_cm1 extends t3lib_SCbase
00035  *
00036  *              SECTION: Standard module initialization
00037  *  138:     function menuConfig()
00038  *  175:     function main()
00039  *  236:     function jumpToUrl(URL)
00040  *  296:     function printContent()
00041  *
00042  *              SECTION: Versioning management
00043  *  322:     function versioningMgm()
00044  *  485:     function pageSubContent($pid,$c=0)
00045  *  539:     function lookForOwnVersions($table,$uid)
00046  *  556:     function adminLinks($table,$row)
00047  *
00048  *              SECTION: Workspace management
00049  *  628:     function workspaceMgm()
00050  *  688:     function displayWorkspaceOverview()
00051  *  758:     function displayWorkspaceOverview_list($pArray)
00052  *  923:     function displayWorkspaceOverview_setInPageArray(&$pArray,$table,$row)
00053  *  936:     function displayWorkspaceOverview_allStageCmd()
00054  *
00055  *              SECTION: Helper functions (REDUNDANT FROM user/ws/index.php - someone could refactor this...)
00056  *  986:     function formatVerId($verId)
00057  *  996:     function formatWorkspace($wsid)
00058  * 1023:     function formatCount($count)
00059  * 1050:     function versionsInOtherWS($table,$uid)
00060  * 1080:     function showStageChangeLog($table,$id,$stageCommands)
00061  * 1129:     function subElements($uid,$treeLevel,$origId=0)
00062  * 1232:     function subElements_getNonPageRecords($tN, $uid, &$recList)
00063  * 1262:     function subElements_renderItem(&$tCell,$tN,$uid,$rec,$origId,$iconMode,$HTMLdata)
00064  * 1331:     function markupNewOriginals()
00065  * 1353:     function createDiffView($table, $diff_1_record, $diff_2_record)
00066  * 1470:     function displayWorkspaceOverview_stageCmd($table,&$rec_off)
00067  * 1557:     function displayWorkspaceOverview_commandLinks($table,&$rec_on,&$rec_off,$vType)
00068  * 1627:     function displayWorkspaceOverview_commandLinksSub($table,$rec,$origId)
00069  *
00070  *              SECTION: Processing
00071  * 1683:     function publishAction()
00072  *
00073  * TOTAL FUNCTIONS: 27
00074  * (This index is automatically created/updated by the extension "extdeveval")
00075  *
00076  */
00077 
00078 
00079     // DEFAULT initialization of a module [BEGIN]
00080 unset($MCONF);
00081 require ('conf.php');
00082 require ($BACK_PATH.'init.php');
00083 require ($BACK_PATH.'template.php');
00084 $LANG->includeLLFile('EXT:version/locallang.xml');
00085     // DEFAULT initialization of a module [END]
00086 
00087 require_once('../ws/class.wslib.php');
00088 
00089 
00090 
00091 /**
00092  * Versioning module, including workspace management
00093  *
00094  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00095  * @package TYPO3
00096  * @subpackage core
00097  */
00098 class tx_version_cm1 extends t3lib_SCbase {
00099 
00100         // Default variables for backend modules
00101     var $MCONF = array();               // Module configuration
00102     var $MOD_MENU = array();            // Module menu items
00103     var $MOD_SETTINGS = array();        // Module session settings
00104 
00105     /**
00106      * document template object
00107      *
00108      * @var mediumDoc
00109      */
00110     var $doc;
00111     var $content;                       // Accumulated content
00112 
00113 
00114         // Internal:
00115     var $showWorkspaceCol = 0;
00116     var $formatWorkspace_cache = array();
00117     var $formatCount_cache = array();
00118     var $targets = array();     // Accumulation of online targets.
00119     var $pageModule = '';           // Name of page module
00120     var $publishAccess = FALSE;
00121     var $be_user_Array = array();
00122     var $stageIndex = array();
00123     var $recIndex = array();
00124     protected $showDraftWorkspace = FALSE; // Determines whether to show the dummy draft workspace
00125 
00126 
00127 
00128 
00129 
00130 
00131     /*********************************
00132      *
00133      * Standard module initialization
00134      *
00135      *********************************/
00136 
00137     /**
00138      * Initialize menu configuration
00139      *
00140      * @return  void
00141      */
00142     function menuConfig()   {
00143 
00144             // fetches the configuration of the version extension
00145         $versionExtconf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['version']);
00146             // show draft workspace only if enabled in the version extensions config
00147         if($versionExtconf['showDraftWorkspace']) {
00148             $this->showDraftWorkspace = TRUE;
00149         }
00150 
00151             // Menu items:
00152         $this->MOD_MENU = array(
00153             'filter' => array(
00154                 1 => $GLOBALS['LANG']->getLL('filter_drafts'),
00155                 2 => $GLOBALS['LANG']->getLL('filter_archive'),
00156                 0 => $GLOBALS['LANG']->getLL('filter_all'),
00157             ),
00158             'display' => array(
00159                 0 => $GLOBALS['LANG']->getLL('liveWorkspace'),
00160                 -98 => $GLOBALS['LANG']->getLL('draftWorkspaces'),
00161                 -99 => $GLOBALS['LANG']->getLL('filter_all'),
00162             ),
00163             'diff' => ''
00164         );
00165 
00166         if($this->showDraftWorkspace === TRUE) {
00167             $this->MOD_MENU['display'][-1] = $GLOBALS['LANG']->getLL('defaultDraft');
00168         }
00169 
00170             // Add workspaces:
00171         if ($GLOBALS['BE_USER']->workspace===0) {   // Spend time on this only in online workspace because it might take time:
00172             $workspaces = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,title,adminusers,members,reviewers','sys_workspace','pid=0'.t3lib_BEfunc::deleteClause('sys_workspace'),'','title');
00173             foreach($workspaces as $rec)    {
00174                 if ($GLOBALS['BE_USER']->checkWorkspace($rec))  {
00175                     $this->MOD_MENU['display'][$rec['uid']] = '['.$rec['uid'].'] '.$rec['title'];
00176                 }
00177             }
00178         }
00179 
00180             // CLEANSE SETTINGS
00181         $this->MOD_SETTINGS = t3lib_BEfunc::getModuleData($this->MOD_MENU, t3lib_div::_GP('SET'), $this->MCONF['name'], 'ses');
00182     }
00183 
00184     /**
00185      * Main function of the module. Write the content to $this->content
00186      *
00187      * @return  void
00188      */
00189     function main() {
00190         global $BE_USER,$LANG,$BACK_PATH,$TCA_DESCR,$TCA,$CLIENT,$TYPO3_CONF_VARS;
00191 
00192             // Template markers
00193         $markers = array(
00194             'CSH' => '',
00195             'FUNC_MENU' => '',
00196             'WS_MENU' => '',
00197             'CONTENT' => ''
00198         );
00199 
00200             // Setting module configuration:
00201         $this->MCONF = $GLOBALS['MCONF'];
00202 
00203         $this->REQUEST_URI = str_replace('&sendToReview=1','',t3lib_div::getIndpEnv('REQUEST_URI'));
00204 
00205             // Draw the header.
00206         $this->doc = t3lib_div::makeInstance('template');
00207         $this->doc->backPath = $BACK_PATH;
00208         $this->doc->setModuleTemplate('templates/version.html');
00209 
00210             // Add styles
00211         $this->doc->inDocStylesArray[$GLOBALS['MCONF']['name']] = '
00212 .version-diff-1 { background-color: green; }
00213 .version-diff-2 { background-color: red; }
00214 ';
00215 
00216             // Setting up the context sensitive menu:
00217         $this->doc->getContextMenuCode();
00218 
00219             // Getting input data:
00220         $this->id = intval(t3lib_div::_GP('id'));       // Page id. If set, indicates activation from Web>Versioning module
00221         if (!$this->id) {
00222             $this->uid = intval(t3lib_div::_GP('uid'));     // Record uid. Goes with table name to indicate specific record
00223             $this->table = t3lib_div::_GP('table');         // Record table. Goes with uid to indicate specific record
00224         } else {
00225             $this->uid = $this->id;
00226             $this->table = 'pages';
00227         }
00228         $this->details = t3lib_div::_GP('details');     // Page id. If set, indicates activation from Web>Versioning module
00229         $this->diffOnly = t3lib_div::_GP('diffOnly');       // Flag. If set, shows only the offline version and with diff-view
00230 
00231             // Force this setting:
00232         $this->MOD_SETTINGS['expandSubElements'] = TRUE;
00233         $this->MOD_SETTINGS['diff'] = $this->details || $this->MOD_SETTINGS['diff']?1:0;
00234 
00235             // Reading the record:
00236         $record = t3lib_BEfunc::getRecord($this->table,$this->uid);
00237         if ($record['pid']==-1) {
00238             $record = t3lib_BEfunc::getRecord($this->table,$record['t3ver_oid']);
00239         }
00240 
00241         $this->recordFound = is_array($record);
00242 
00243         $pidValue = $this->table==='pages' ? $this->uid : $record['pid'];
00244 
00245             // Checking access etc.
00246         if ($this->recordFound && $TCA[$this->table]['ctrl']['versioningWS'])   {
00247             $this->doc->form='<form action="" method="post">';
00248             $this->uid = $record['uid'];    // Might have changed if new live record was found!
00249 
00250                 // Access check!
00251                 // The page will show only if there is a valid page and if this page may be viewed by the user
00252             $this->pageinfo = t3lib_BEfunc::readPageAccess($pidValue,$this->perms_clause);
00253             $access = is_array($this->pageinfo) ? 1 : 0;
00254 
00255             if (($pidValue && $access) || ($BE_USER->user['admin'] && !$pidValue))  {
00256 
00257                     // JavaScript
00258                 $this->doc->JScode.= '
00259                     <script language="javascript" type="text/javascript">
00260                         script_ended = 0;
00261                         function jumpToUrl(URL) {
00262                             window.location.href = URL;
00263                         }
00264 
00265                         function hlSubelements(origId, verId, over, diffLayer)  {   //
00266                             if (over)   {
00267                                 document.getElementById(\'orig_\'+origId).attributes.getNamedItem("class").nodeValue = \'typo3-ver-hl\';
00268                                 document.getElementById(\'ver_\'+verId).attributes.getNamedItem("class").nodeValue = \'typo3-ver-hl\';
00269                                 if (diffLayer)  {
00270                                     document.getElementById(\'diff_\'+verId).style.visibility = \'visible\';
00271                                 }
00272                             } else {
00273                                 document.getElementById(\'orig_\'+origId).attributes.getNamedItem("class").nodeValue = \'typo3-ver\';
00274                                 document.getElementById(\'ver_\'+verId).attributes.getNamedItem("class").nodeValue = \'typo3-ver\';
00275                                 if (diffLayer)  {
00276                                     document.getElementById(\'diff_\'+verId).style.visibility = \'hidden\';
00277                                 }
00278                             }
00279                         }
00280                     </script>
00281                 ';
00282 
00283                     // If another page module was specified, replace the default Page module with the new one
00284                 $newPageModule = trim($BE_USER->getTSConfigVal('options.overridePageModule'));
00285                 $this->pageModule = t3lib_BEfunc::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
00286 
00287                     // Setting publish access permission for workspace:
00288                 $this->publishAccess = $BE_USER->workspacePublishAccess($BE_USER->workspace);
00289 
00290                     // Render content:
00291                 if ($this->id)  {
00292                     $this->workspaceMgm();
00293                 } else {
00294                     $this->versioningMgm();
00295                 }
00296             }
00297 
00298             $this->content.=$this->doc->spacer(10);
00299 
00300                 // Setting up the buttons and markers for docheader
00301             $docHeaderButtons = $this->getButtons();
00302             $markers['CSH'] = $docHeaderButtons['csh'];
00303             $markers['FUNC_MENU'] = t3lib_BEfunc::getFuncMenu($this->id, 'SET[function]', $this->MOD_SETTINGS['function'], $this->MOD_MENU['function']);
00304             $markers['WS_MENU'] = $this->workspaceMenu();
00305             $markers['CONTENT'] = $this->content;
00306         } else {
00307                 // If no access or id value, create empty document
00308             $this->content = $this->doc->section($LANG->getLL('clickAPage_header'), $LANG->getLL('clickAPage_content'), 0, 1);
00309 
00310                 // Setting up the buttons and markers for docheader
00311             $docHeaderButtons = $this->getButtons();
00312             $markers['CONTENT'] = $this->content;
00313         }
00314             // Build the <body> for the module
00315         $this->content = $this->doc->startPage($LANG->getLL('title'));
00316         $this->content.= $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
00317         $this->content.= $this->doc->endPage();
00318         $this->content = $this->doc->insertStylesAndJS($this->content);
00319     }
00320 
00321     /**
00322      * Outputs accumulated module content to browser.
00323      *
00324      * @return  void
00325      */
00326     function printContent() {
00327         echo $this->content;
00328     }
00329 
00330     /**
00331      * Create the panel of buttons for submitting the form or otherwise perform operations.
00332      *
00333      * @return  array   all available buttons as an assoc. array
00334      */
00335     protected function getButtons() {
00336         global $TCA, $LANG, $BACK_PATH, $BE_USER;
00337 
00338         $buttons = array(
00339             'csh' => '',
00340             'view' => '',
00341             'record_list' => '',
00342             'shortcut' => '',
00343         );
00344             // CSH
00345         //$buttons['csh'] = t3lib_BEfunc::cshItem('_MOD_web_txversionM1', '', $GLOBALS['BACK_PATH']);
00346 
00347         if ($this->recordFound && $TCA[$this->table]['ctrl']['versioningWS']) {
00348                 // View page
00349             $buttons['view'] = '<a href="#" onclick="' . htmlspecialchars(t3lib_BEfunc::viewOnClick($this->pageinfo['uid'], $BACK_PATH, t3lib_BEfunc::BEgetRootLine($this->pageinfo['uid']))) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.showPage', TRUE) . '">' .
00350                         t3lib_iconWorks::getSpriteIcon('actions-document-view') .
00351                     '</a>';
00352 
00353                 // Shortcut
00354             if ($BE_USER->mayMakeShortcut())    {
00355                 $buttons['shortcut'] = $this->doc->makeShortcutIcon('id, edit_record, pointer, new_unique_uid, search_field, search_levels, showLimit', implode(',', array_keys($this->MOD_MENU)), $this->MCONF['name']);
00356             }
00357 
00358                 // If access to Web>List for user, then link to that module.
00359             $buttons['record_list'] = t3lib_BEfunc::getListViewLink(
00360                 array(
00361                     'id' => $this->pageinfo['uid'],
00362                     'returnUrl' => t3lib_div::getIndpEnv('REQUEST_URI'),
00363                 ),
00364                 '',
00365                 $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.showList')
00366             );
00367         }
00368         return $buttons;
00369     }
00370 
00371 
00372 
00373 
00374 
00375 
00376 
00377 
00378     /******************************
00379      *
00380      * Versioning management
00381      *
00382      ******************************/
00383 
00384     /**
00385      * Management of versions for record
00386      *
00387      * @return  void
00388      */
00389     function versioningMgm()    {
00390         global $TCA;
00391 
00392             // Diffing:
00393         $diff_1 = t3lib_div::_POST('diff_1');
00394         $diff_2 = t3lib_div::_POST('diff_2');
00395         if (t3lib_div::_POST('do_diff'))    {
00396             $content='';
00397             $content.='<h3>' . $GLOBALS['LANG']->getLL('diffing') . ':</h3>';
00398             if ($diff_1 && $diff_2) {
00399                 $diff_1_record = t3lib_BEfunc::getRecord($this->table, $diff_1);
00400                 $diff_2_record = t3lib_BEfunc::getRecord($this->table, $diff_2);
00401 
00402                 if (is_array($diff_1_record) && is_array($diff_2_record))   {
00403                     t3lib_div::loadTCA($this->table);
00404                     $t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff');
00405 
00406                     $tRows=array();
00407                                 $tRows[] = '
00408                                     <tr class="bgColor5 tableheader">
00409                                         <td>' . $GLOBALS['LANG']->getLL('fieldname') . '</td>
00410                                         <td width="98%">' . $GLOBALS['LANG']->getLL('coloredDiffView') . ':</td>
00411                                     </tr>
00412                                 ';
00413                     foreach($diff_1_record as $fN => $fV)   {
00414                         if ($TCA[$this->table]['columns'][$fN] && $TCA[$this->table]['columns'][$fN]['config']['type']!='passthrough' && !t3lib_div::inList('t3ver_label',$fN)) {
00415                             if (strcmp($diff_1_record[$fN],$diff_2_record[$fN]))    {
00416 
00417                                 $diffres = $t3lib_diff_Obj->makeDiffDisplay(
00418                                     t3lib_BEfunc::getProcessedValue($this->table,$fN,$diff_2_record[$fN],0,1),
00419                                     t3lib_BEfunc::getProcessedValue($this->table,$fN,$diff_1_record[$fN],0,1)
00420                                 );
00421 
00422                                 $tRows[] = '
00423                                     <tr class="bgColor4">
00424                                         <td>'.$fN.'</td>
00425                                         <td width="98%">'.$diffres.'</td>
00426                                     </tr>
00427                                 ';
00428                             }
00429                         }
00430                     }
00431 
00432                     if (count($tRows)>1)    {
00433                         $content .= '<table border="0" cellpadding="1" cellspacing="1" width="100%">' . implode('', $tRows) . '</table><br /><br />';
00434                     } else {
00435                         $content .= $GLOBALS['LANG']->getLL('recordsMatchesCompletely');
00436                     }
00437                 } else $content .= $GLOBALS['LANG']->getLL('errorRecordsNotFound');
00438             } else {
00439                 $content .= $GLOBALS['LANG']->getLL('errorDiffSources');
00440             }
00441         }
00442 
00443             // Element:
00444         $record = t3lib_BEfunc::getRecord($this->table,$this->uid);
00445         $recordIcon = t3lib_iconWorks::getSpriteIconForRecord($this->table, $record);
00446         $recTitle = t3lib_BEfunc::getRecordTitle($this->table,$record,TRUE);
00447 
00448             // Display versions:
00449         $content.='
00450             '.$recordIcon.$recTitle.'
00451             <form name="theform" action="'.str_replace('&sendToReview=1','',$this->REQUEST_URI).'" method="post">
00452             <table border="0" cellspacing="1" cellpadding="1">';
00453             $content.='
00454                 <tr class="bgColor5 tableheader">
00455                     <td>&nbsp;</td>
00456                     <td>&nbsp;</td>
00457                     <td title="' . $GLOBALS['LANG']->getLL('tblHeaderDesc_title') . '">' . $GLOBALS['LANG']->getLL('tblHeader_title') . '</td>
00458                     <td title="' . $GLOBALS['LANG']->getLL('tblHeaderDesc_uid') . '">' . $GLOBALS['LANG']->getLL('tblHeader_uid') . '</td>
00459                     <td title="' . $GLOBALS['LANG']->getLL('tblHeaderDesc_t3ver_oid') . '">' . $GLOBALS['LANG']->getLL('tblHeader_t3ver_oid') . '</td>
00460                     <td title="' . $GLOBALS['LANG']->getLL('tblHeaderDesc_t3ver_id') . '">' . $GLOBALS['LANG']->getLL('tblHeader_t3ver_id') . '</td>
00461                     <td title="' . $GLOBALS['LANG']->getLL('tblHeaderDesc_t3ver_wsid') . '">' . $GLOBALS['LANG']->getLL('tblHeader_t3ver_wsid') . '</td>
00462                     <td title="' . $GLOBALS['LANG']->getLL('tblHeaderDesc_t3ver_state') . '">' . $GLOBALS['LANG']->getLL('tblHeader_t3ver_state') . '</td>
00463                     <td title="' . $GLOBALS['LANG']->getLL('tblHeaderDesc_t3ver_stage') . '">' . $GLOBALS['LANG']->getLL('tblHeader_t3ver_stage') . '</td>
00464                     <td title="' . $GLOBALS['LANG']->getLL('tblHeaderDesc_t3ver_count') . '">' . $GLOBALS['LANG']->getLL('tblHeader_t3ver_count') . '</td>
00465                     <td title="' . $GLOBALS['LANG']->getLL('tblHeaderDesc_pid') . '">' . $GLOBALS['LANG']->getLL('tblHeader_pid') . '</td>
00466                     <td title="' . $GLOBALS['LANG']->getLL('tblHeaderDesc_t3ver_label') . '">' . $GLOBALS['LANG']->getLL('tblHeader_t3ver_label') . '</td>
00467                     <td colspan="2"><input type="submit" name="do_diff" value="' . $GLOBALS['LANG']->getLL('diff') . '" /></td>
00468                 </tr>';
00469 
00470         $versions = t3lib_BEfunc::selectVersionsOfRecord($this->table, $this->uid, '*', $GLOBALS['BE_USER']->workspace);
00471         foreach($versions as $row)  {
00472             $adminLinks = $this->adminLinks($this->table,$row);
00473 
00474             $content.='
00475                 <tr class="' . ($row['uid'] != $this->uid ? 'bgColor4' : 'bgColor2 tableheader') . '">
00476                     <td>'.($row['uid']!=$this->uid ? '<a href="'.$this->doc->issueCommand('&cmd['.$this->table.']['.$this->uid.'][version][swapWith]='.$row['uid'].'&cmd['.$this->table.']['.$this->uid.'][version][action]=swap').'" title="' . $GLOBALS['LANG']->getLL('swapWithCurrent', TRUE) . '">'.
00477                         t3lib_iconWorks::getSpriteIcon('actions-version-swap-version') .
00478                         '</a>' /* (
00479                             $this->table == 'pages' ?
00480                             '<a href="'.$this->doc->issueCommand('&cmd['.$this->table.']['.$this->uid.'][version][action]=swap&cmd['.$this->table.']['.$this->uid.'][version][swapWith]='.$row['uid'].'&cmd['.$this->table.']['.$this->uid.'][version][swapContent]=1').'">'.
00481                         '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/insert2.gif','width="14" height="14"').' alt="" title="Publish page AND content!" />'.
00482                         '</a>'.
00483                             '<a href="'.$this->doc->issueCommand('&cmd['.$this->table.']['.$this->uid.'][version][action]=swap&cmd['.$this->table.']['.$this->uid.'][version][swapWith]='.$row['uid'].'&cmd['.$this->table.']['.$this->uid.'][version][swapContent]=ALL').'">'.
00484                         '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/insert4.gif','width="14" height="14"').' alt="" title="Publish page AND content! - AND ALL SUBPAGES!" />'.
00485                         '</a>' : '') */ : t3lib_iconWorks::getSpriteIcon('status-status-current', array('title' =>  $GLOBALS['LANG']->getLL('currentOnlineVersion', TRUE)))) . '</td>
00486                     <td nowrap="nowrap">'.$adminLinks.'</td>
00487                     <td nowrap="nowrap">'.t3lib_BEfunc::getRecordTitle($this->table,$row,TRUE).'</td>
00488                     <td>'.$row['uid'].'</td>
00489                     <td>'.$row['t3ver_oid'].'</td>
00490                     <td>'.$row['t3ver_id'].'</td>
00491                     <td>'.$row['t3ver_wsid'].'</td>
00492                     <td>'.$row['t3ver_state'].'</td>
00493                     <td>'.$row['t3ver_stage'].'</td>
00494                     <td>'.$row['t3ver_count'].'</td>
00495                     <td>'.$row['pid'].'</td>
00496                     <td nowrap="nowrap"><a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick('&edit['.$this->table.']['.$row['uid'].']=edit&columnsOnly=t3ver_label',$this->doc->backPath)).'" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:cm.edit', TRUE) . '">' .
00497                             t3lib_iconWorks::getSpriteIcon('actions-document-open') .
00498                         '</a>' . htmlspecialchars($row['t3ver_label']) . '</td>
00499                     <td class="version-diff-1"><input type="radio" name="diff_1" value="'.$row['uid'].'"'.($diff_1==$row['uid'] ? ' checked="checked"':'').'/></td>
00500                     <td class="version-diff-2"><input type="radio" name="diff_2" value="'.$row['uid'].'"'.($diff_2==$row['uid'] ? ' checked="checked"':'').'/></td>
00501                 </tr>';
00502 
00503                 // Show sub-content if the table is pages AND it is not the online branch (because that will mostly render the WHOLE tree below - not smart;)
00504             if ($this->table == 'pages' && $row['uid']!=$this->uid) {
00505                 $sub = $this->pageSubContent($row['uid']);
00506 
00507                 if ($sub)   {
00508                     $content.='
00509                         <tr>
00510                             <td></td>
00511                             <td></td>
00512                             <td colspan="10">'.$sub.'</td>
00513                             <td colspan="2"></td>
00514                         </tr>';
00515                 }
00516             }
00517         }
00518         $content.='</table></form>';
00519 
00520         $this->content .= $this->doc->section($GLOBALS['LANG']->getLL('title'), $content, 0, 1);
00521 
00522 
00523             // Create new:
00524         $content='
00525 
00526             <form action="'.$this->doc->backPath.'tce_db.php" method="post">
00527             ' . $GLOBALS['LANG']->getLL('tblHeader_t3ver_label') . ': <input type="text" name="cmd[' . $this->table . '][' . $this->uid . '][version][label]" /><br />
00528             '.(($this->table == 'pages' && $GLOBALS['TYPO3_CONF_VARS']['BE']['elementVersioningOnly'] == FALSE)? '<select name="cmd['.$this->table.']['.$this->uid.'][version][treeLevels]">
00529                 '.($GLOBALS['BE_USER']->workspaceVersioningTypeAccess(0) ? '<option value="0">' . $GLOBALS['LANG']->getLL('cmdPid0') . '</option>' : '').'
00530                 '.($GLOBALS['BE_USER']->workspaceVersioningTypeAccess(1) ? '<option value="100">' . $GLOBALS['LANG']->getLL('cmdPid100') . '</option>' : '').'
00531                 '.($GLOBALS['BE_USER']->workspaceVersioningTypeAccess(-1) ? '<option value="-1">' . $GLOBALS['LANG']->getLL('cmdPid1') . '</option>' : '').'
00532             </select>' : '').'
00533             <br /><input type="hidden" name="cmd[' . $this->table . '][' . $this->uid . '][version][action]" value="new" />
00534             <input type="hidden" name="prErr" value="1" />
00535             <input type="hidden" name="redirect" value="'.htmlspecialchars($this->REQUEST_URI).'" />
00536             <input type="submit" name="_" value="' . $GLOBALS['LANG']->getLL('createNewVersion') . '" />
00537             ' . t3lib_TCEforms::getHiddenTokenField('tceAction') . '
00538             </form>
00539 
00540         ';
00541 
00542         $this->content.=$this->doc->spacer(15);
00543         $this->content.=$this->doc->section($GLOBALS['LANG']->getLL('createNewVersion'), $content,0,1);
00544 
00545     }
00546 
00547     /**
00548      * Recursively look for children for page version with $pid
00549      *
00550      * @param   integer     UID of page record for which to look up sub-elements following that version
00551      * @param   integer     Counter, do not set (limits to 100 levels)
00552      * @return  string      Table with content if any
00553      */
00554     function pageSubContent($pid,$c=0)  {
00555         global $TCA;
00556 
00557         $tableNames = t3lib_div::removeArrayEntryByValue(array_keys($TCA),'pages');
00558         $tableNames[] = 'pages';
00559 
00560         foreach($tableNames as $tN) {
00561                 // Basically list ALL tables - not only those being copied might be found!
00562             #if ($TCA[$tN]['ctrl']['versioning_followPages'] || $tN=='pages')   {
00563                 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $tN, 'pid='.intval($pid).t3lib_BEfunc::deleteClause($tN), '', ($TCA[$tN]['ctrl']['sortby'] ? $TCA[$tN]['ctrl']['sortby'] : ''));
00564 
00565                 if ($GLOBALS['TYPO3_DB']->sql_num_rows($mres))  {
00566                     $content.='
00567                         <tr>
00568                             <td colspan="4" class="'.($TCA[$tN]['ctrl']['versioning_followPages'] ? 'bgColor6' : ($tN=='pages' ? 'bgColor5' : 'bgColor-10')).'"'.(!$TCA[$tN]['ctrl']['versioning_followPages'] && $tN!='pages' ? ' style="color: #666666; font-style:italic;"':'').'>'.$tN.'</td>
00569                         </tr>';
00570                     while ($subrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))  {
00571                         $ownVer = $this->lookForOwnVersions($tN,$subrow['uid']);
00572                         $content.='
00573                             <tr>
00574                                 <td>'.$this->adminLinks($tN,$subrow).'</td>
00575                                 <td>'.$subrow['uid'].'</td>
00576                                 '.($ownVer>1 ? '<td style="font-weight: bold; background-color: yellow;"><a href="index.php?table='.rawurlencode($tN).'&uid='.$subrow['uid'].'">'.($ownVer-1).'</a></td>' : '<td></td>').'
00577                                 <td width="98%">'.t3lib_BEfunc::getRecordTitle($tN,$subrow,TRUE).'</td>
00578                             </tr>';
00579 
00580                         if ($tN == 'pages' && $c<100)   {
00581                             $sub = $this->pageSubContent($subrow['uid'],$c+1);
00582 
00583                             if ($sub)   {
00584                                 $content.='
00585                                     <tr>
00586                                         <td></td>
00587                                         <td></td>
00588                                         <td></td>
00589                                         <td width="98%">'.$sub.'</td>
00590                                     </tr>';
00591                             }
00592                         }
00593                     }
00594                 }
00595             #}
00596         }
00597 
00598         return $content ? '<table border="1" cellpadding="1" cellspacing="0" width="100%">'.$content.'</table>' : '';
00599     }
00600 
00601     /**
00602      * Look for number of versions of a record
00603      *
00604      * @param   string      Table name
00605      * @param   integer     Record uid
00606      * @return  integer     Number of versions for record, false if none.
00607      */
00608     function lookForOwnVersions($table,$uid)    {
00609         global $TCA;
00610 
00611         $versions = t3lib_BEfunc::selectVersionsOfRecord($table, $uid, 'uid');
00612         if (is_array($versions))    {
00613             return count($versions);
00614         }
00615         return FALSE;
00616     }
00617 
00618     /**
00619      * Administrative links for a table / record
00620      *
00621      * @param   string      Table name
00622      * @param   array       Record for which administrative links are generated.
00623      * @return  string      HTML link tags.
00624      */
00625     function adminLinks($table,$row)    {
00626         global $BE_USER;
00627 
00628             // Edit link:
00629         $adminLink = '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick('&edit['.$table.']['.$row['uid'].']=edit',$this->doc->backPath)).'" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:cm.edit', TRUE) . '">'.
00630                             t3lib_iconWorks::getSpriteIcon('actions-document-open') .
00631                         '</a>';
00632 
00633             // Delete link:
00634         $adminLink.= '<a href="'.htmlspecialchars($this->doc->issueCommand('&cmd['.$table.']['.$row['uid'].'][delete]=1')).'" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:cm.delete', TRUE) . '">' .
00635                             t3lib_iconWorks::getSpriteIcon('actions-edit-delete') .
00636                         '</a>';
00637 
00638 
00639 
00640         if ($table == 'pages')  {
00641 
00642                 // If another page module was specified, replace the default Page module with the new one
00643             $newPageModule = trim($BE_USER->getTSConfigVal('options.overridePageModule'));
00644             $pageModule = t3lib_BEfunc::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
00645 
00646                 // Perform some acccess checks:
00647             $a_wl = $BE_USER->check('modules','web_list');
00648             $a_wp = t3lib_extMgm::isLoaded('cms') && $BE_USER->check('modules',$pageModule);
00649 
00650             $adminLink.='<a href="#" onclick="top.loadEditId('.$row['uid'].');top.goToModule(\''.$pageModule.'\'); return false;">'.
00651                             t3lib_iconWorks::getSpriteIcon('actions-page-open') .
00652                         '</a>';
00653             $adminLink.='<a href="#" onclick="top.loadEditId('.$row['uid'].');top.goToModule(\'web_list\'); return false;">'.
00654                             t3lib_iconWorks::getSpriteIcon('actions-system-list-open') .
00655                         '</a>';
00656 
00657                 // "View page" icon is added:
00658             $adminLink.='<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($row['uid'],$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($row['uid']))).'">'.
00659                     t3lib_iconWorks::getSpriteIcon('actions-document-view') .
00660                 '</a>';
00661         } else {
00662             if ($row['pid']==-1)    {
00663                 $getVars = '&ADMCMD_vPrev['.rawurlencode($table.':'.$row['t3ver_oid']).']='.$row['uid'];
00664 
00665                     // "View page" icon is added:
00666                 $adminLink.='<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($row['_REAL_PID'],$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($row['_REAL_PID']),'','',$getVars)).'">'.
00667                         t3lib_iconWorks::getSpriteIcon('actions-document-view') .
00668                     '</a>';
00669             }
00670         }
00671 
00672         return $adminLink;
00673     }
00674 
00675 
00676 
00677 
00678 
00679 
00680 
00681 
00682 
00683 
00684 
00685     /******************************
00686      *
00687      * Workspace management
00688      *
00689      ******************************/
00690 
00691     /**
00692      * Management of workspace for page ID
00693      * Called when $this->id is set.
00694      *
00695      * @return  void
00696      */
00697     function workspaceMgm() {
00698 
00699             // Perform workspace publishing action if buttons are pressed:
00700         $errors = $this->publishAction();
00701 
00702             // Generate workspace overview:
00703         $WSoverview = $this->displayWorkspaceOverview();
00704 
00705             // Buttons for publish / swap:
00706         $actionLinks = '<br />';
00707         if ($GLOBALS['BE_USER']->workspace!==0) {
00708             if ($this->publishAccess)   {
00709                 $actionLinks.= '<input type="submit" name="_publish" value="' . $GLOBALS['LANG']->getLL('publishPage') . '" onclick="return confirm(\'' . sprintf($GLOBALS['LANG']->getLL('publishPageQuestion'), $GLOBALS['BE_USER']->workspaceRec['publish_access'] & 1 ? $GLOBALS['LANG']->getLL('publishPageQuestionStage') : '') . '\');"/>';
00710                 if ($GLOBALS['BE_USER']->workspaceSwapAccess()) {
00711                     $actionLinks.= '<input type="submit" name="_swap" value="' . $GLOBALS['LANG']->getLL('swapPage') . '" onclick="return confirm(\'' . sprintf($GLOBALS['LANG']->getLL('swapPageQuestion'), $GLOBALS['BE_USER']->workspaceRec['publish_access'] & 1 ? $GLOBALS['LANG']->getLL('publishPageQuestionStage') : '') . '\');" />';
00712                 }
00713             } else {
00714                 $actionLinks.= $this->doc->icons(1) . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_user_ws.xml:no_publish_permission');
00715             }
00716         }
00717 
00718         $actionLinks.= '<input type="submit" name="_" value="' . $GLOBALS['LANG']->getLL('refresh') . '" />';
00719         $actionLinks.= '<input type="submit" name="_previewLink" value="' . $GLOBALS['LANG']->getLL('previewLink') . '" />';
00720         $actionLinks.= '<input type="checkbox" class="checkbox" name="_previewLink_wholeWorkspace" id="_previewLink_wholeWorkspace" value="1" /><label for="_previewLink_wholeWorkspace">' . $GLOBALS['LANG']->getLL('allowPreviewOfWholeWorkspace') . '</label>';
00721         $actionLinks.= $this->displayWorkspaceOverview_allStageCmd();
00722 
00723         if ($actionLinks || count($errors)) {
00724             $this->content .= $this->doc->section('', $actionLinks . (count($errors) ? '<h3>' . $GLOABLS['LANG']->getLL('errors') . '</h3><br />' . implode('<br />', $errors) . '<hr />' : ''), 0, 1);
00725         }
00726 
00727         if (t3lib_div::_POST('_previewLink'))   {
00728             $ttlHours = intval($GLOBALS['BE_USER']->getTSConfigVal('options.workspaces.previewLinkTTLHours'));
00729             $ttlHours = ($ttlHours ? $ttlHours : 24*2);
00730 
00731             if (t3lib_div::_POST('_previewLink_wholeWorkspace'))    {
00732                 $previewUrl = t3lib_BEfunc::getViewDomain($this->id) . '/index.php?ADMCMD_prev=' . t3lib_BEfunc::compilePreviewKeyword('', $GLOBALS['BE_USER']->user['uid'], 60*60*$ttlHours, $GLOBALS['BE_USER']->workspace) . '&id=' . intval($this->id);
00733             } else {
00734                 $params = 'id='.$this->id.'&ADMCMD_previewWS='.$GLOBALS['BE_USER']->workspace;
00735                 $previewUrl = t3lib_BEfunc::getViewDomain($this->id) . '/index.php?ADMCMD_prev=' . t3lib_BEfunc::compilePreviewKeyword($params, $GLOBALS['BE_USER']->user['uid'], 60*60*$ttlHours);
00736             }
00737             $this->content .= $this->doc->section($GLOBALS['LANG']->getLL('previewUrl'), sprintf($GLOBALS['LANG']->getLL('previewInstruction'), $ttlHours) . '<br /><br /><a target="_blank" href="' . htmlspecialchars($previewUrl) . '">' . $previewUrl . '</a>', 0, 1);
00738         }
00739 
00740             // Output overview content:
00741         $this->content.= $this->doc->spacer(15);
00742         $this->content.= $this->doc->section($this->details ? $GLOBALS['LANG']->getLL('versionDetails') : $GLOBALS['LANG']->getLL('wsManagement'), $WSoverview,0,1);
00743 
00744     }
00745 
00746     function workspaceMenu() {
00747         if($this->id) {
00748             $menu = '';
00749             if ($GLOBALS['BE_USER']->workspace===0) {
00750                 $menu.= t3lib_BEfunc::getFuncMenu($this->id,'SET[filter]',$this->MOD_SETTINGS['filter'],$this->MOD_MENU['filter']);
00751                 $menu.= t3lib_BEfunc::getFuncMenu($this->id,'SET[display]',$this->MOD_SETTINGS['display'],$this->MOD_MENU['display']);
00752             }
00753             if (!$this->details && $GLOBALS['BE_USER']->workspace && !$this->diffOnly)  {
00754                 $menu.= t3lib_BEfunc::getFuncCheck($this->id,'SET[diff]',$this->MOD_SETTINGS['diff'],'','','id="checkDiff"').' <label for="checkDiff">' . $GLOBALS['LANG']->getLL('showDiffView') . '</label>';
00755             }
00756 
00757             if ($menu)  {
00758                 return $menu;
00759             }
00760         }
00761     }
00762 
00763     /**
00764      * Rendering the overview of versions in the current workspace
00765      *
00766      * @return  string      HTML (table)
00767      * @see ws/index.php for sister function!
00768      */
00769     function displayWorkspaceOverview() {
00770 
00771             // Initialize variables:
00772         $this->showWorkspaceCol = $GLOBALS['BE_USER']->workspace===0 && $this->MOD_SETTINGS['display']<=-98;
00773 
00774             // Get usernames and groupnames
00775         $be_group_Array = t3lib_BEfunc::getListGroupNames('title,uid');
00776         $groupArray = array_keys($be_group_Array);
00777         $this->be_user_Array = t3lib_BEfunc::getUserNames();
00778         if (!$GLOBALS['BE_USER']->isAdmin())        $this->be_user_Array = t3lib_BEfunc::blindUserNames($this->be_user_Array,$groupArray,1);
00779 
00780             // Initialize Workspace ID and filter-value:
00781         if ($GLOBALS['BE_USER']->workspace===0) {
00782             $wsid = $this->details ? -99 : $this->MOD_SETTINGS['display'];      // Set wsid to the value from the menu (displaying content of other workspaces)
00783             $filter = $this->details ? 0 : $this->MOD_SETTINGS['filter'];
00784         } else {
00785             $wsid = $GLOBALS['BE_USER']->workspace;
00786             $filter = 0;
00787         }
00788 
00789             // Initialize workspace object and request all pending versions:
00790         $wslibObj = t3lib_div::makeInstance('wslib');
00791 
00792             // Selecting ALL versions belonging to the workspace:
00793         $versions = $wslibObj->selectVersionsInWorkspace($wsid, $filter, -99, $this->uid);  // $this->uid is the page id of LIVE record.
00794 
00795             // Traverse versions and build page-display array:
00796         $pArray = array();
00797         foreach($versions as $table => $records)    {
00798             foreach($records as $rec)   {
00799                 $pageIdField = $table==='pages' ? 't3ver_oid' : 'realpid';
00800                 $this->displayWorkspaceOverview_setInPageArray(
00801                     $pArray,
00802                     $table,
00803                     $rec
00804                 );
00805             }
00806         }
00807 
00808             // Make header of overview:
00809         $tableRows = array();
00810         if (count($pArray)) {
00811             $tableRows[] = '
00812                 <tr class="bgColor5 tableheader">
00813                     '.($this->diffOnly?'':'<td nowrap="nowrap" colspan="2">' . $GLOBALS['LANG']->getLL('liveVersion') . '</td>').'
00814                     <td nowrap="nowrap" colspan="2">' . $GLOBALS['LANG']->getLL('wsVersions') . '</td>
00815                     <td nowrap="nowrap"'.($this->diffOnly?' colspan="2"':' colspan="4"').'>' . $GLOBALS['LANG']->getLL('controls') . '</td>
00816                 </tr>';
00817 
00818                 // Add lines from overview:
00819             $tableRows = array_merge($tableRows, $this->displayWorkspaceOverview_list($pArray));
00820 
00821             $table = '<table border="0" cellpadding="0" cellspacing="1" class="lrPadding workspace-overview">'.implode('',$tableRows).'</table>';
00822         } else $table = '';
00823 
00824         $returnUrl = t3lib_div::sanitizeLocalUrl(t3lib_div::_GP('returnUrl'));
00825         $linkBack = t3lib_div::_GP('returnUrl') ? '<a href="' . htmlspecialchars($returnUrl) . '" class="typo3-goBack">' .
00826                 t3lib_iconWorks::getSpriteIcon('actions-view-go-back') . $GLOBALS['LANG']->getLL('goBack', TRUE) .
00827             '</a><br /><br />' : '';
00828         $resetDiffOnly = $this->diffOnly ? '<a href="index.php?id=' . intval($this->id) . '" class="typo3-goBack">' . $GLOBALS['LANG']->getLL('showAllInformation') . '</a><br /><br />' : '';
00829 
00830         $versionSelector = $GLOBALS['BE_USER']->workspace ? $this->doc->getVersionSelector($this->id) : '';
00831 
00832         return $versionSelector.$linkBack.$resetDiffOnly.$table.$this->markupNewOriginals();
00833     }
00834 
00835     /**
00836      * Rendering the content for the publish / review overview:
00837      * (Made for internal recursive calling)
00838      *
00839      * @param   array       Storage of the elements to display (see displayWorkspaceOverview() / displayWorkspaceOverview_setInPageArray())
00840      * @return  array       Table rows, see displayWorkspaceOverview()
00841      */
00842     function displayWorkspaceOverview_list($pArray) {
00843         global $TCA;
00844 
00845             // If there ARE elements on this level, print them:
00846         $warnAboutVersions_nonPages = FALSE;
00847         $warnAboutVersions_page = FALSE;
00848         if (is_array($pArray))  {
00849             foreach($pArray as $table => $oidArray) {
00850                 foreach($oidArray as $oid => $recs) {
00851 
00852                         // Get CURRENT online record and icon based on "t3ver_oid":
00853                     $rec_on = t3lib_BEfunc::getRecord($table,$oid);
00854                     $icon = t3lib_iconWorks::getSpriteIconForRecord($table, $rec_on, array('title' => t3lib_BEfunc::getRecordIconAltText($rec_on,$table)));
00855                     if ($GLOBALS['BE_USER']->workspace===0) {   // Only edit online records if in ONLINE workspace:
00856                         $icon = $this->doc->wrapClickMenuOnIcon($icon, $table, $rec_on['uid'], 1, '', '+edit,view,info,delete');
00857                     }
00858 
00859                         // Online version display:
00860                         // Create the main cells which will span over the number of versions there is.
00861                     $verLinkUrl = $TCA[$table]['ctrl']['versioningWS'];
00862                     $origElement = $icon.
00863                         ($verLinkUrl ? '<a href="'.htmlspecialchars('index.php?table='.$table.'&uid='.$rec_on['uid']).'">' : '').
00864                         t3lib_BEfunc::getRecordTitle($table,$rec_on,TRUE).
00865                         ($verLinkUrl ? '</a>' : '');
00866                     $mainCell_rowSpan = count($recs)>1 ? ' rowspan="'.count($recs).'"' : '';
00867                     $mainCell = '
00868                                 <td align="center"'.$mainCell_rowSpan.'>'.$this->formatVerId($rec_on['t3ver_id']).'</td>
00869                                 <td nowrap="nowrap"'.$mainCell_rowSpan.'>'.
00870                                     $origElement.
00871                                     '###SUB_ELEMENTS###'.   // For substitution with sub-elements, if any.
00872                                 '</td>';
00873 
00874                         // Offline versions display:
00875                         // Traverse the versions of the element
00876                     foreach($recs as $rec)  {
00877 
00878                             // Get the offline version record and icon:
00879                         $rec_off = t3lib_BEfunc::getRecord($table,$rec['uid']);
00880 
00881                         // Prepare swap-mode values:
00882                         if ($table==='pages' && $rec_off['t3ver_swapmode']!=-1) {
00883                             if ($rec_off['t3ver_swapmode']>0)   {
00884                                 $vType = 'branch';
00885                             } else {
00886                                 $vType = 'page';
00887                             }
00888                         } else {
00889                             $vType = 'element';
00890                         }
00891 
00892                         // Get icon
00893                         $icon = t3lib_iconWorks::getSpriteIconForRecord($table, $rec_off, array('title' => t3lib_BEfunc::getRecordIconAltText($rec_off, $table)));
00894                         $tempUid = ($table != 'pages' || $vType==='branch' || $GLOBALS['BE_USER']->workspace===0 ? $rec_off['uid'] : $rec_on['uid']);
00895                         $icon = $this->doc->wrapClickMenuOnIcon($icon, $table, $tempUid, 1, '', '+edit,' . ($table == 'pages' ? 'view,info,' : '') . 'delete');
00896 
00897                             // Prepare diff-code:
00898                         if ($this->MOD_SETTINGS['diff'] || $this->diffOnly) {
00899                             $diffCode = '';
00900                             list($diffHTML,$diffPct) = $this->createDiffView($table, $rec_off, $rec_on);
00901                             if ($rec_on['t3ver_state']==1)  {   // New record:
00902                                 $diffCode.= $this->doc->icons(1) . $GLOBALS['LANG']->getLL('newElement') . '<br />';
00903                                 $diffCode.= $diffHTML;
00904                             } elseif ($rec_off['t3ver_state']==2)   {
00905                                 $diffCode.= $this->doc->icons(2) . $GLOBALS['LANG']->getLL('deletedElement') . '<br />';
00906                             } elseif ($rec_on['t3ver_state']==3)    {
00907                                 $diffCode.= $this->doc->icons(1) . $GLOBALS['LANG']->getLL('moveToPlaceholder') . '<br />';
00908                             } elseif ($rec_off['t3ver_state']==4)   {
00909                                 $diffCode.= $this->doc->icons(1) . $GLOBALS['LANG']->getLL('moveToPointer') . '<br />';
00910                             } else {
00911                                 $diffCode.= ($diffPct<0 ? $GLOBALS['LANG']->getLL('notAvailable') : ($diffPct ? $diffPct . '% ' . $GLOBALS['LANG']->getLL('change') : ''));
00912                                 $diffCode.= $diffHTML;
00913                             }
00914                         } else $diffCode = '';
00915 
00916                         switch($vType) {
00917                             case 'element':
00918                                 $swapLabel = $GLOBALS['LANG']->getLL('element');
00919                                 $swapClass = 'ver-element';
00920                                 $warnAboutVersions_nonPages = $warnAboutVersions_page;  // Setting this if sub elements are found with a page+content (must be rendered prior to this of course!)
00921                             break;
00922                             case 'page':
00923                                 $swapLabel = $GLOBALS['LANG']->getLL('page');
00924                                 $swapClass = 'ver-page';
00925                                 $warnAboutVersions_page = !$this->showWorkspaceCol;     // This value is true only if multiple workspaces are shown and we need the opposite here.
00926                             break;
00927                             case 'branch':
00928                                 $swapLabel = $GLOBALS['LANG']->getLL('branch');
00929                                 $swapClass = 'ver-branch';
00930                             break;
00931                         }
00932 
00933                             // Modify main cell based on first version shown:
00934                         $subElements = array();
00935                         if ($table==='pages' && $rec_off['t3ver_swapmode']!=-1 && $mainCell)    {   // For "Page" and "Branch" swap modes where $mainCell is still carrying content (only first version)
00936                             $subElements['on'] = $this->subElements($rec_on['uid'], $rec_off['t3ver_swapmode']);
00937                             $subElements['off'] = $this->subElements($rec_off['uid'],$rec_off['t3ver_swapmode'],$rec_on['uid']);
00938                         }
00939                         $mainCell = str_replace('###SUB_ELEMENTS###', $subElements['on'], $mainCell);
00940 
00941                             // Create version element:
00942                         $versionsInOtherWS = $this->versionsInOtherWS($table, $rec_on['uid']);
00943                         $versionsInOtherWSWarning = $versionsInOtherWS && $GLOBALS['BE_USER']->workspace !== 0 ? '<br />' . $this->doc->icons(2) . $GLOBALS['LANG']->getLL('otherVersions') . $versionsInOtherWS : '';
00944                         $multipleWarning = (!$mainCell && $GLOBALS['BE_USER']->workspace !== 0 ? '<br />' . $this->doc->icons(3) . '<strong>' . $GLOBALS['LANG']->getLL('multipleVersions') . '</strong>' : '');
00945                         $verWarning = $warnAboutVersions || ($warnAboutVersions_nonPages && $GLOBALS['TCA'][$table]['ctrl']['versioning_followPages']) ? '<br />' . $this->doc->icons(3) . '<strong>' . $GLOBALS['LANG']->getLL('versionInVersion') . '</strong>' : '';
00946                         $verElement = $icon.
00947                             (!$this->details ? '<a href="'.htmlspecialchars($this->doc->backPath.t3lib_extMgm::extRelPath('version').'cm1/index.php?id='.($table==='pages'?$rec_on['uid']:$rec_on['pid']).'&details='.rawurlencode($table.':'.$rec_off['uid']).'&returnUrl='.rawurlencode($this->REQUEST_URI)).'">' : '').
00948                             t3lib_BEfunc::getRecordTitle($table,$rec_off,TRUE).
00949                             (!$this->details ? '</a>' : '').
00950                             $versionsInOtherWSWarning.
00951                             $multipleWarning.
00952                             $verWarning;
00953 
00954                         $ctrlTable = '
00955                                 <td nowrap="nowrap">'.$this->showStageChangeLog($table,$rec_off['uid'],$this->displayWorkspaceOverview_stageCmd($table,$rec_off)).'</td>
00956                                 <td nowrap="nowrap" class="'.$swapClass.'">'.
00957                                     $this->displayWorkspaceOverview_commandLinks($table,$rec_on,$rec_off,$vType).
00958                                     htmlspecialchars($swapLabel).
00959                                     '&nbsp;&nbsp;</td>
00960                                 '.(!$this->diffOnly?'<td nowrap="nowrap"><strong>' . $GLOBALS['LANG']->getLL('lifecycle')  . ':</strong> '.htmlspecialchars($this->formatCount($rec_off['t3ver_count'])).'</td>'.       // Lifecycle
00961                                     ($this->showWorkspaceCol ? '
00962                                 <td nowrap="nowrap">&nbsp;&nbsp;<strong>' . $GLOBALS['LANG']->getLL('workspace')  . ':</strong> '.htmlspecialchars($this->formatWorkspace($rec_off['t3ver_wsid'])).'</td>' : ''):'');
00963 
00964                         if ($diffCode)  {
00965                             $verElement = $verElement.'
00966                             <br /><strong>' . $GLOBALS['LANG']->getLL('diffToLiveElement') . '</strong>
00967                             <table border="0" cellpadding="0" cellspacing="0" class="ver-verElement">
00968                                 <tr>
00969                                     <td class="c-diffCell">'.$diffCode.'</td>
00970                                 </tr>
00971                             </table>';
00972                         }
00973 
00974 
00975                             // Create version cell:
00976                         $verCell = '
00977                                 <td align="center">'.$this->formatVerId($rec_off['t3ver_id']).'</td>
00978                                 <td nowrap="nowrap">'.
00979                                     $verElement.
00980                                     $subElements['off'].
00981                                     '</td>
00982                                 ';
00983 
00984                             // Compile table row:
00985                         $tableRows[] = '
00986                             <tr class="bgColor4">
00987                                 '.
00988                                 ($this->diffOnly?'':$mainCell).
00989                                 $verCell.
00990                                 $ctrlTable.
00991                                 '
00992                             </tr>';
00993 
00994                             // Reset the main cell:
00995                         $mainCell = '';
00996 
00997                     }
00998                 }
00999             }
01000         }
01001 
01002         return $tableRows;
01003     }
01004 
01005     /**
01006      * Building up of the $pArray
01007      * (Internal)
01008      *
01009      * @param   array       Array that is built up with the page tree structure
01010      * @param   string      Table name
01011      * @param   array       Table row
01012      * @return  void        $pArray is passed by reference and modified internally
01013      */
01014     function displayWorkspaceOverview_setInPageArray(&$pArray,$table,$row)  {
01015         if (!$this->details || $this->details==$table.':'.$row['uid'])  {
01016             $pArray[$table][$row['t3ver_oid']][] = $row;
01017         }
01018     }
01019 
01020     /**
01021      * Links to stage change of a version
01022      *
01023      * @param   string      Table name
01024      * @param   array       Offline record (version)
01025      * @return  string      HTML content, mainly link tags and images.
01026      */
01027     function displayWorkspaceOverview_allStageCmd() {
01028 
01029         $table = t3lib_div::_GP('table');
01030         if ($table && $table!='pages')  {
01031             $uid = t3lib_div::_GP('uid');
01032             if ($rec_off = t3lib_BEfunc::getRecordWSOL($table,$uid)) {
01033                 $uid = $rec_off['_ORIG_uid'];
01034             }
01035         } else $table = '';
01036 
01037         if ($table) {
01038             if ($uid && $this->recIndex[$table][$uid])  {
01039                 $sId = $this->recIndex[$table][$uid];
01040                 switch($sId)    {
01041                     case 1:
01042                         $label = $GLOBALS['LANG']->getLL('commentForReviewer');
01043                     break;
01044                     case 10:
01045                         $label = $GLOBALS['LANG']->getLL('commentForPublisher');
01046                     break;
01047                 }
01048             } else $sId = 0;
01049         } else {
01050             if (count($this->stageIndex[1]))    {   // Review:
01051                 $sId = 1;
01052                 $color = '#666666';
01053                 $label = $GLOBALS['LANG']->getLL('sendItemsToReview') . $GLOBALS['LANG']->getLL('commentForReviewer');
01054                 $titleAttrib = $GLOBALS['LANG']->getLL('sendAllToReview');
01055             } elseif(count($this->stageIndex[10]))  {   // Publish:
01056                 $sId = 10;
01057                 $color = '#6666cc';
01058                 $label = $GLOBALS['LANG']->getLL('approveToPublish') . $GLOBALS['LANG']->getLL('commentForPublisher');
01059                 $titleAttrib = $GLOBALS['LANG']->getLL('approveAllToPublish');
01060             } else {
01061                 $sId = 0;
01062             }
01063         }
01064 
01065         if ($sId>0) {
01066             $issueCmd = '';
01067             $itemCount = 0;
01068 
01069             if ($table && $uid && $this->recIndex[$table][$uid])    {
01070                 $issueCmd.='&cmd['.$table.']['.$uid.'][version][action]=setStage';
01071                 $issueCmd.='&cmd['.$table.']['.$uid.'][version][stageId]='.$this->recIndex[$table][$uid];
01072             } else {
01073                 foreach($this->stageIndex[$sId] as $table => $uidArray) {
01074                     $issueCmd.='&cmd['.$table.']['.implode(',',$uidArray).'][version][action]=setStage';
01075                     $issueCmd.='&cmd['.$table.']['.implode(',',$uidArray).'][version][stageId]='.$sId;
01076                     $itemCount+=count($uidArray);
01077                 }
01078             }
01079 
01080             $onClick = 'var commentTxt=window.prompt("'.sprintf($label,$itemCount).'","");
01081                             if (commentTxt!=null) {window.location.href="'.$this->doc->issueCommand($issueCmd,$this->REQUEST_URI).'&generalComment="+escape(commentTxt);}';
01082 
01083             if (t3lib_div::_GP('sendToReview')) {
01084                 $onClick.= ' else {window.location.href = "'.$this->REQUEST_URI.'"}';
01085                 $actionLinks.=
01086                     $this->doc->wrapScriptTags($onClick);
01087             } else {
01088                 $onClick.= ' return false;';
01089                 $actionLinks.=
01090                     '<input type="submit" name="_" value="'.htmlspecialchars($titleAttrib).'" onclick="'.htmlspecialchars($onClick).'" />';
01091             }
01092         } elseif (t3lib_div::_GP('sendToReview'))   {
01093             $onClick = 'window.location.href = "'.$this->REQUEST_URI.'";';
01094             $actionLinks.=
01095                 $this->doc->wrapScriptTags($onClick);
01096         } else $actionLinks = '';
01097 
01098         return $actionLinks;
01099     }
01100 
01101 
01102 
01103 
01104 
01105 
01106     /**************************************
01107      *
01108      * Helper functions (REDUNDANT FROM user/ws/index.php - someone could refactor this...)
01109      *
01110      *************************************/
01111 
01112     /**
01113      * Formatting the version number for HTML output
01114      *
01115      * @param   integer     Version number
01116      * @return  string      Version number for output
01117      */
01118     function formatVerId($verId)    {
01119         return '1.'.$verId;
01120     }
01121 
01122     /**
01123      * Formatting workspace ID into a visual label
01124      *
01125      * @param   integer     Workspace ID
01126      * @return  string      Workspace title
01127      */
01128     function formatWorkspace($wsid) {
01129 
01130             // Render, if not cached:
01131         if (!isset($this->formatWorkspace_cache[$wsid]))    {
01132             switch($wsid)   {
01133                 case -1:
01134                     $this->formatWorkspace_cache[$wsid] = $GLOBALS['LANG']->getLL('offline');
01135                 break;
01136                 case 0:
01137                     $this->formatWorkspace_cache[$wsid] = '';   // Does not output anything for ONLINE because it might confuse people to think that the elemnet IS online which is not the case - only that it exists as an offline version in the online workspace...
01138                 break;
01139                 default:
01140                     $titleRec = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('title', 'sys_workspace', 'uid=' . intval($wsid) . t3lib_BEfunc::deleteClause('sys_workspace'));
01141                     $this->formatWorkspace_cache[$wsid] = '['.$wsid.'] '.$titleRec['title'];
01142                 break;
01143             }
01144         }
01145 
01146         return $this->formatWorkspace_cache[$wsid];
01147     }
01148 
01149     /**
01150      * Format publishing count for version (lifecycle state)
01151      *
01152      * @param   integer     t3ver_count value (number of times it has been online)
01153      * @return  string      String translation of count.
01154      */
01155     function formatCount($count)    {
01156 
01157             // Render, if not cached:
01158         if (!isset($this->formatCount_cache[$count]))   {
01159             switch($count)  {
01160                 case 0:
01161                     $this->formatCount_cache[$count] = $GLOBALS['LANG']->getLL('draft');
01162                 break;
01163                 case 1:
01164                     $this->formatCount_cache[$count] = $GLOBALS['LANG']->getLL('archive');
01165                 break;
01166                 default:
01167                     $this->formatCount_cache[$count] = sprintf($GLOBALS['LANG']->getLL('publishedXTimes'), $count);
01168                 break;
01169             }
01170         }
01171 
01172         return $this->formatCount_cache[$count];
01173     }
01174 
01175     /**
01176      * Looking for versions of a record in other workspaces than the current
01177      *
01178      * @param   string      Table name
01179      * @param   integer     Record uid
01180      * @return  string      List of other workspace IDs
01181      */
01182     function versionsInOtherWS($table,$uid) {
01183 
01184             // Check for duplicates:
01185             // Select all versions of record NOT in this workspace:
01186         $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
01187             't3ver_wsid',
01188             $table,
01189             'pid=-1
01190                 AND t3ver_oid='.intval($uid).'
01191                 AND t3ver_wsid!='.intval($GLOBALS['BE_USER']->workspace).'
01192                 AND (t3ver_wsid=-1 OR t3ver_wsid>0)'.
01193                 t3lib_BEfunc::deleteClause($table),
01194             '',
01195             't3ver_wsid',
01196             '',
01197             't3ver_wsid'
01198         );
01199         if (count($rows))   {
01200             return implode(',',array_keys($rows));
01201         }
01202     }
01203 
01204     /**
01205      * Looks up stage changes for version and displays a formatted view on mouseover.
01206      *
01207      * @param   string      Table name
01208      * @param   integer     Record ID
01209      * @param   string      HTML string to wrap the mouseover around (should be stage change links)
01210      * @return  string      HTML code.
01211      */
01212     function showStageChangeLog($table,$id,$stageCommands)  {
01213         $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
01214             'log_data,tstamp,userid',
01215             'sys_log',
01216             'action=6 and details_nr=30
01217                 AND tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table,'sys_log').'
01218                 AND recuid='.intval($id)
01219         );
01220 
01221         $entry = array();
01222         foreach($rows as $dat)  {
01223             $data = unserialize($dat['log_data']);
01224             $username = $this->be_user_Array[$dat['userid']] ? $this->be_user_Array[$dat['userid']]['username'] : '['.$dat['userid'].']';
01225 
01226             switch($data['stage'])  {
01227                 case 1:
01228                     $text = $GLOBALS['LANG']->getLL('stage.sentToReview');
01229                 break;
01230                 case 10:
01231                     $text = $GLOBALS['LANG']->getLL('stage.approvedForPublish');
01232                 break;
01233                 case -1:
01234                     $text = $GLOBALS['LANG']->getLL('stage.rejectedElement');
01235                 break;
01236                 case 0:
01237                     $text = $GLOBALS['LANG']->getLL('stage.resetToEdit');
01238                 break;
01239                 default:
01240                     $text = $GLOBALS['LANG']->getLL('stage.undefined');
01241                 break;
01242             }
01243             $text = t3lib_BEfunc::dateTime($dat['tstamp']).': "'.$username.'" '.$text;
01244             $text.= ($data['comment'] ? '<br />' . $GLOBALS['LANG']->getLL('userComment') . ': <em>' . htmlspecialchars($data['comment']) . '</em>' : '');
01245 
01246             $entry[] = $text;
01247         }
01248 
01249         return count($entry) ? '<span onmouseover="document.getElementById(\'log_' . $table . $id . '\').style.visibility = \'visible\';" onmouseout="document.getElementById(\'log_' . $table . $id . '\').style.visibility = \'hidden\';">' . $stageCommands . ' (' . count($entry) . ')</span>' .
01250                 '<div class="t3-version-infolayer logLayer" id="log_' . $table . $id . '">' . implode('<hr/>', array_reverse($entry)) . '</div>' : $stageCommands;
01251     }
01252 
01253     /**
01254      * Creates display of sub elements of a page when the swap mode is either "Page" or "Branch" (0 / ALL)
01255      *
01256      * @param   integer     Page uid (for either online or offline version, but it MUST have swapmode/treeLevel set to >0 (not -1 indicating element versioning)
01257      * @param   integer     The treeLevel value, >0 indicates "branch" while 0 means page+content. (-1 would have meant element versioning, but that should never happen for a call to this function!)
01258      * @param   integer     For offline versions; This is t3ver_oid, the original ID of the online page.
01259      * @return  string      HTML content.
01260      */
01261     function subElements($uid,$treeLevel,$origId=0) {
01262         global $TCA;
01263 
01264         if (!$this->details && ($GLOBALS['BE_USER']->workspace===0 || !$this->MOD_SETTINGS['expandSubElements']))   {   // In online workspace we have a reduced view because otherwise it will bloat the listing:
01265             return '<br />
01266                     <img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/ol/joinbottom.gif','width="18" height="16"').' align="top" alt="" title="" />'.
01267                     ($origId ?
01268                         '<a href="'.htmlspecialchars($this->doc->backPath.t3lib_extMgm::extRelPath('version').'cm1/index.php?id='.$uid.'&details='.rawurlencode('pages:'.$uid).'&returnUrl='.rawurlencode($this->REQUEST_URI)).'">'.
01269                         '<span class="typo3-dimmed"><em>' . $GLOBALS['LANG']->getLL('subElementsClick')  . '</em><span></a>' :
01270                         '<span class="typo3-dimmed"><em>' . $GLOBALS['LANG']->getLL('subElements') . '</em><span>');
01271         } else {    // For an offline workspace, show sub elements:
01272 
01273             $tCell = array();
01274 
01275                 // Find records that follow pages when swapping versions:
01276             $recList = array();
01277             foreach($TCA as $tN => $tCfg)   {
01278                 if ($tN!='pages' && ($treeLevel>0 || $TCA[$tN]['ctrl']['versioning_followPages']))  {
01279                     $this->subElements_getNonPageRecords($tN, $uid, $recList);
01280                 }
01281             }
01282 
01283                 // Render records collected above:
01284             $elCount = count($recList)-1;
01285             foreach($recList as $c => $comb)    {
01286                 list($tN,$rec) = $comb;
01287 
01288                 $this->subElements_renderItem(
01289                     $tCell,
01290                     $tN,
01291                     $uid,
01292                     $rec,
01293                     $origId,
01294                     $c==$elCount && $treeLevel==0 ? 1 : 0,      // If true, will show bottom-join icon.
01295                     ''
01296                 );
01297             }
01298 
01299                 // For branch, dive into the subtree:
01300             if ($treeLevel>0) {
01301 
01302                     // Drawing tree:
01303                 $tree = t3lib_div::makeInstance('t3lib_pageTree');
01304                 $tree->init('AND '.$GLOBALS['BE_USER']->getPagePermsClause(1));
01305                 $tree->makeHTML = 2;        // 2=Also rendering depth-data into the result array
01306                 $tree->getTree($uid, 99, '');
01307 
01308                     // Traverse page tree:
01309                 foreach($tree->tree as $data)   {
01310 
01311                         // Render page in table cell:
01312                     $this->subElements_renderItem(
01313                         $tCell,
01314                         'pages',
01315                         $uid,
01316                         t3lib_BEfunc::getRecord('pages',$data['row']['uid']),   // Needs all fields, at least more than what is given in $data['row']...
01317                         $origId,
01318                         2,      // 2=the join icon and icon for the record is not rendered for pages (where all is in $data['HTML']
01319                         $data['HTML']
01320                     );
01321 
01322                         // Find all records from page and collect in $recList:
01323                     $recList = array();
01324                     foreach($TCA as $tN => $tCfg)   {
01325                         if ($tN!=='pages')  {
01326                             $this->subElements_getNonPageRecords($tN, $data['row']['uid'], $recList);
01327                         }
01328                     }
01329 
01330                         // Render records collected above:
01331                     $elCount = count($recList)-1;
01332                     foreach($recList as $c => $comb)    {
01333                         list($tN,$rec) = $comb;
01334 
01335                         $this->subElements_renderItem(
01336                             $tCell,
01337                             $tN,
01338                             $uid,
01339                             $rec,
01340                             $origId,
01341                             $c==$elCount?1:0,   // If true, will show bottom-join icon.
01342                             $data['HTML_depthData']
01343                         );
01344                     }
01345                 }
01346             }
01347 
01348             return '
01349                     <!-- Sub-element tree for versions -->
01350                     <table border="0" cellpadding="0" cellspacing="1" class="ver-subtree">
01351                         '.implode('',$tCell).'
01352                     </table>';
01353         }
01354     }
01355 
01356     /**
01357      * Select records from a table and add them to recList
01358      *
01359      * @param   string      Table name (from TCA)
01360      * @param   integer     PID to select records from
01361      * @param   array       Array where records are accumulated, passed by reference
01362      * @return  void
01363      */
01364     function subElements_getNonPageRecords($tN, $uid, &$recList)    {
01365         global $TCA;
01366 
01367         $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
01368             '*',
01369             $tN,
01370             'pid='.intval($uid).
01371                 ($TCA[$tN]['ctrl']['versioningWS'] ? ' AND t3ver_state=0' : '').
01372                 t3lib_BEfunc::deleteClause($tN),
01373             '',
01374             $TCA[$tN]['ctrl']['sortby'] ? $TCA[$tN]['ctrl']['sortby'] : $GLOBALS['TYPO3_DB']->stripOrderBy($TCA[$tN]['ctrl']['default_sortby'])
01375         );
01376 
01377         foreach($records as $rec)   {
01378             $recList[] = array($tN,$rec);
01379         }
01380     }
01381 
01382     /**
01383      * Render a single item in a subelement list into a table row:
01384      *
01385      * @param   array       Table rows, passed by reference
01386      * @param   string      Table name
01387      * @param   integer     Page uid for which the subelements are selected/shown
01388      * @param   array       Row of element in list
01389      * @param   integer     The uid of the online version of $uid. If zero it means we are drawing a row for the online version itself while a value means we are drawing display for an offline version.
01390      * @param   integer     Mode of icon display: 0=not the last, 1= is the last in list (make joinbottom icon then), 2=do not shown icons are all (for pages from the page tree already rendered)
01391      * @param   string      Prefix HTML data (icons for tree rendering)
01392      * @return  void        (Content accumulated in $tCell!)
01393      */
01394     function subElements_renderItem(&$tCell,$tN,$uid,$rec,$origId,$iconMode,$HTMLdata)  {
01395         global $TCA;
01396 
01397             // Initialize:
01398         $origUidFields = $TCA[$tN]['ctrl']['origUid'];
01399         $diffCode = '';
01400 
01401         if ($origUidFields) {   // If there is a field for this table with original uids we will use that to connect records:
01402             if (!$origId)   {   // In case we are displaying the online originals:
01403                 $this->targets['orig_'.$uid.'_'.$tN.'_'.$rec['uid']] = $rec;    // Build up target array (important that
01404                 $tdParams =  ' id="orig_'.$uid.'_'.$tN.'_'.$rec['uid'].'" class="typo3-ver"';       // Setting ID of the table row
01405             } else {    // Version branch:
01406                 if ($this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]])   {   // If there IS a corresponding original record...:
01407 
01408                         // Prepare Table row parameters:
01409                     $tdParams =  ' onmouseover="hlSubelements(\''.$origId.'_'.$tN.'_'.$rec[$origUidFields].'\', \''.$uid.'_'.$tN.'_'.$rec[$origUidFields].'\', 1, '.($this->MOD_SETTINGS['diff']==2?1:0).');"'.
01410                                 ' onmouseout="hlSubelements(\''.$origId.'_'.$tN.'_'.$rec[$origUidFields].'\', \''.$uid.'_'.$tN.'_'.$rec[$origUidFields].'\', 0, '.($this->MOD_SETTINGS['diff']==2?1:0).');"'.
01411                                 ' id="ver_'.$uid.'_'.$tN.'_'.$rec[$origUidFields].'" class="typo3-ver"';
01412 
01413                         // Create diff view:
01414                     if ($this->MOD_SETTINGS['diff'])    {
01415                         list($diffHTML,$diffPct) = $this->createDiffView($tN, $rec, $this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]]);
01416 
01417                         if ($this->MOD_SETTINGS['diff']==2) {
01418                             $diffCode =
01419                                 ($diffPct ? '<span class="nobr">'.$diffPct.'% change</span>' : '-').
01420                                 '<div style="visibility: hidden; position: absolute;" id="diff_'.$uid.'_'.$tN.'_'.$rec[$origUidFields].'" class="diffLayer">'.
01421                                 $diffHTML.
01422                                 '</div>';
01423                         } else {
01424                             $diffCode =
01425                                 ($diffPct<0 ? $GLOBALS['LANG']->getLL('notAvailable') : ($diffPct ? $diffPct . '% ' . $GLOBALS['LANG']->getLL('change') : '')).
01426                                 $diffHTML;
01427                         }
01428                     }
01429 
01430                         // Unsetting the target fields allows us to mark all originals without a version in the subtree (see ->markupNewOriginals())
01431                     unset($this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]]);
01432                 } else {    // No original record, so must be new:
01433                     $tdParams =  ' class="typo3-ver-new"';
01434                 }
01435             }
01436         } else {    // If no original uid column is supported for this table we are forced NOT to display any diff or highlighting.
01437             $tdParams = ' class="typo3-ver-noComp"';
01438         }
01439 
01440             // Compile the cell:
01441         $tCell[] = '
01442                         <tr'.$tdParams.'>
01443                             <td class="iconTitle">'.
01444                                 $HTMLdata.
01445                                 ($iconMode < 2 ?
01446                                     '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/ol/join'.($iconMode ? 'bottom' : '').'.gif','width="18" height="16"').' alt="" />'.
01447                                     t3lib_iconWorks::getSpriteIconForRecord($tN, $rec) : '').
01448                                 t3lib_BEfunc::getRecordTitle($tN, $rec, TRUE).
01449                             '</td>
01450                             <td class="cmdCell">'.
01451                                 $this->displayWorkspaceOverview_commandLinksSub($tN,$rec,$origId).
01452                             '</td>'.($origId ? '<td class="diffCell">'.
01453                                 $diffCode.
01454                             '</td>':'').'
01455                         </tr>';
01456     }
01457 
01458     /**
01459      * JavaScript code to mark up new records that are online (in sub element lists)
01460      *
01461      * @return  string      HTML javascript section
01462      */
01463     function markupNewOriginals()   {
01464 
01465         if (count($this->targets))  {
01466             $scriptCode = '';
01467             foreach($this->targets as $key => $rec) {
01468                 $scriptCode.='
01469                     document.getElementById(\''.$key.'\').attributes.getNamedItem("class").nodeValue = \'typo3-ver-new\';
01470                 ';
01471             }
01472 
01473             return $this->doc->wrapScriptTags($scriptCode);
01474         }
01475     }
01476 
01477     /**
01478      * Create visual difference view of two records. Using t3lib_diff library
01479      *
01480      * @param   string      Table name
01481      * @param   array       New version record (green)
01482      * @param   array       Old version record (red)
01483      * @return  array       Array with two keys (0/1) with HTML content / percentage integer (if -1, then it means N/A) indicating amount of change
01484      */
01485     function createDiffView($table, $diff_1_record, $diff_2_record) {
01486         global $TCA;
01487 
01488             // Initialize:
01489         $pctChange = 'N/A';
01490 
01491             // Check that records are arrays:
01492         if (is_array($diff_1_record) && is_array($diff_2_record))   {
01493 
01494                 // Load full table description and initialize diff-object:
01495             t3lib_div::loadTCA($table);
01496             $t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff');
01497 
01498                 // Add header row:
01499             $tRows = array();
01500             $tRows[] = '
01501                 <tr class="bgColor5 tableheader">
01502                     <td>' . $GLOBALS['LANG']->getLL('fieldname')  . ':</td>
01503                     <td width="98%" nowrap="nowrap">' . $GLOBALS['LANG']->getLL('coloredDiffView') . ':</td>
01504                 </tr>
01505             ';
01506 
01507                 // Initialize variables to pick up string lengths in:
01508             $allStrLen = 0;
01509             $diffStrLen = 0;
01510 
01511                 // Traversing the first record and process all fields which are editable:
01512             foreach($diff_1_record as $fN => $fV)   {
01513                 if ($TCA[$table]['columns'][$fN] && $TCA[$table]['columns'][$fN]['config']['type']!='passthrough' && !t3lib_div::inList('t3ver_label',$fN)) {
01514 
01515                         // Check if it is files:
01516                     $isFiles = FALSE;
01517                     if (strcmp(trim($diff_1_record[$fN]),trim($diff_2_record[$fN])) &&
01518                             $TCA[$table]['columns'][$fN]['config']['type']=='group' &&
01519                             $TCA[$table]['columns'][$fN]['config']['internal_type']=='file')    {
01520 
01521                             // Initialize:
01522                         $uploadFolder = $TCA[$table]['columns'][$fN]['config']['uploadfolder'];
01523                         $files1 = array_flip(t3lib_div::trimExplode(',', $diff_1_record[$fN],1));
01524                         $files2 = array_flip(t3lib_div::trimExplode(',', $diff_2_record[$fN],1));
01525 
01526                             // Traverse filenames and read their md5 sum:
01527                         foreach($files1 as $filename => $tmp)   {
01528                             $files1[$filename] = @is_file(PATH_site.$uploadFolder.'/'.$filename) ? md5(t3lib_div::getUrl(PATH_site.$uploadFolder.'/'.$filename)) : $filename;
01529                         }
01530                         foreach($files2 as $filename => $tmp)   {
01531                             $files2[$filename] = @is_file(PATH_site.$uploadFolder.'/'.$filename) ? md5(t3lib_div::getUrl(PATH_site.$uploadFolder.'/'.$filename)) : $filename;
01532                         }
01533 
01534                             // Implode MD5 sums and set flag:
01535                         $diff_1_record[$fN] = implode(' ',$files1);
01536                         $diff_2_record[$fN] = implode(' ',$files2);
01537                         $isFiles = TRUE;
01538                     }
01539 
01540                         // If there is a change of value:
01541                     if (strcmp(trim($diff_1_record[$fN]),trim($diff_2_record[$fN])))    {
01542 
01543 
01544                             // Get the best visual presentation of the value and present that:
01545                         $val1 = t3lib_BEfunc::getProcessedValue($table,$fN,$diff_2_record[$fN],0,1);
01546                         $val2 = t3lib_BEfunc::getProcessedValue($table,$fN,$diff_1_record[$fN],0,1);
01547 
01548                             // Make diff result and record string lenghts:
01549                         $diffres = $t3lib_diff_Obj->makeDiffDisplay($val1,$val2,$isFiles?'div':'span');
01550                         $diffStrLen+= $t3lib_diff_Obj->differenceLgd;
01551                         $allStrLen+= strlen($val1.$val2);
01552 
01553                             // If the compared values were files, substituted MD5 hashes:
01554                         if ($isFiles)   {
01555                             $allFiles = array_merge($files1,$files2);
01556                             foreach($allFiles as $filename => $token)   {
01557                                 if (strlen($token)==32 && strstr($diffres,$token))  {
01558                                     $filename =
01559                                         t3lib_BEfunc::thumbCode(array($fN=>$filename),$table,$fN,$this->doc->backPath).
01560                                         $filename;
01561                                     $diffres = str_replace($token,$filename,$diffres);
01562                                 }
01563                             }
01564                         }
01565 
01566                             // Add table row with result:
01567                         $tRows[] = '
01568                             <tr class="bgColor4">
01569                                 <td>'.htmlspecialchars($GLOBALS['LANG']->sL(t3lib_BEfunc::getItemLabel($table,$fN))).'</td>
01570                                 <td width="98%">'.$diffres.'</td>
01571                             </tr>
01572                         ';
01573                     } else {
01574                             // Add string lengths even if value matched - in this was the change percentage is not high if only a single field is changed:
01575                         $allStrLen+=strlen($diff_1_record[$fN].$diff_2_record[$fN]);
01576                     }
01577                 }
01578             }
01579 
01580                 // Calculate final change percentage:
01581             $pctChange = $allStrLen ? ceil($diffStrLen*100/$allStrLen) : -1;
01582 
01583                 // Create visual representation of result:
01584             if (count($tRows)>1)    {
01585                 $content.= '<table border="0" cellpadding="1" cellspacing="1" class="diffTable">'.implode('',$tRows).'</table>';
01586             } else {
01587                 $content.= '<span class="nobr">'.$this->doc->icons(1) . $GLOBALS['LANG']->getLL('completeMatch') . '</span>';
01588             }
01589         } else $content.= $this->doc->icons(3) . $GLOBALS['LANG']->getLL('errorRecordsNotFound');
01590 
01591             // Return value:
01592         return array($content,$pctChange);
01593     }
01594 
01595     /**
01596      * Links to stage change of a version
01597      *
01598      * @param   string      Table name
01599      * @param   array       Offline record (version)
01600      * @return  string      HTML content, mainly link tags and images.
01601      */
01602     function displayWorkspaceOverview_stageCmd($table,&$rec_off)    {
01603 #debug($rec_off['t3ver_stage']);
01604         switch((int)$rec_off['t3ver_stage'])    {
01605             case 0:
01606                 $sId = 1;
01607                 $sLabel = $GLOBALS['LANG']->getLL('editing');
01608                 $color = '#666666';
01609                 $label = $GLOBALS['LANG']->getLL('commentForReviewer');
01610                 $titleAttrib = $GLOBALS['LANG']->getLL('sendToReview');
01611             break;
01612             case 1:
01613                 $sId = 10;
01614                 $sLabel = $GLOBALS['LANG']->getLL('review');
01615                 $color = '#6666cc';
01616                 $label = $GLOBALS['LANG']->getLL('commentForPublisher');
01617                 $titleAttrib = $GLOBALS['LANG']->getLL('approveForPublishing');
01618             break;
01619             case 10:
01620                 $sLabel = $GLOBALS['LANG']->getLL('publish');
01621                 $color = '#66cc66';
01622             break;
01623             case -1:
01624                 $sLabel = $this->doc->icons(2) . $GLOBALS['LANG']->getLL('rejected');
01625                 $sId = 0;
01626                 $color = '#ff0000';
01627                 $label = $GLOBALS['LANG']->getLL('comment');
01628                 $titleAttrib = $GLOBALS['LANG']->getLL('resetStage');
01629             break;
01630             default:
01631                 $sLabel = $GLOBALS['LANG']->getLL('undefined');
01632                 $sId = 0;
01633                 $color = '';
01634             break;
01635         }
01636 #debug($sId);
01637 
01638         $raiseOk = !$GLOBALS['BE_USER']->workspaceCannotEditOfflineVersion($table,$rec_off);
01639 
01640         if ($raiseOk && $rec_off['t3ver_stage']!=-1)    {
01641             $onClick = 'var commentTxt=window.prompt("' . $GLOBALS['LANG']->getLL('rejectExplain') . '","");
01642                             if (commentTxt!=null) {window.location.href="'.$this->doc->issueCommand(
01643                             '&cmd['.$table.']['.$rec_off['uid'].'][version][action]=setStage'.
01644                             '&cmd['.$table.']['.$rec_off['uid'].'][version][stageId]=-1'
01645                             ).'&cmd['.$table.']['.$rec_off['uid'].'][version][comment]="+escape(commentTxt);}'.
01646                             ' return false;';
01647                 // Reject:
01648             $actionLinks.=
01649                 '<a href="#" onclick="'.htmlspecialchars($onClick).'" title="' . $GLOBALS['LANG']->getLL('reject', TRUE) . '">'.
01650                     t3lib_iconWorks::getSpriteIcon('actions-move-down') .
01651                 '</a>';
01652         } else {
01653                 // Reject:
01654             $actionLinks.=
01655                 '<img src="'.$this->doc->backPath.'gfx/clear.gif" width="14" height="14" alt="" align="top" title="" />';
01656         }
01657 
01658         $actionLinks.= '<span style="background-color: '.$color.'; color: white;">'.$sLabel.'</span>';
01659 
01660             // Raise
01661         if ($raiseOk)   {
01662             $onClick = 'var commentTxt=window.prompt("'.$label.'","");
01663                             if (commentTxt!=null) {window.location.href="'.$this->doc->issueCommand(
01664                             '&cmd['.$table.']['.$rec_off['uid'].'][version][action]=setStage'.
01665                             '&cmd['.$table.']['.$rec_off['uid'].'][version][stageId]='.$sId
01666                             ).'&cmd['.$table.']['.$rec_off['uid'].'][version][comment]="+escape(commentTxt);}'.
01667                             ' return false;';
01668             if ($rec_off['t3ver_stage']!=10)    {
01669                 $actionLinks.=
01670                     '<a href="#" onclick="'.htmlspecialchars($onClick).'" title="' . htmlspecialchars($titleAttrib) . '">' .
01671                         t3lib_iconWorks::getSpriteIcon('actions-move-up') .
01672                     '</a>';
01673 
01674                 $this->stageIndex[$sId][$table][] = $rec_off['uid'];
01675                 $this->recIndex[$table][$rec_off['uid']] = $sId;
01676             }
01677         }
01678         return $actionLinks;
01679     }
01680 
01681     /**
01682      * Links to publishing etc of a version
01683      *
01684      * @param   string      Table name
01685      * @param   array       Online record
01686      * @param   array       Offline record (version)
01687      * @param   string      Swap type, "branch", "page" or "element"
01688      * @return  string      HTML content, mainly link tags and images.
01689      */
01690     function displayWorkspaceOverview_commandLinks($table,&$rec_on,&$rec_off,$vType)    {
01691         if ($this->publishAccess && (!($GLOBALS['BE_USER']->workspaceRec['publish_access']&1) || (int)$rec_off['t3ver_stage']===-10))   {
01692             $actionLinks =
01693                 '<a href="'.htmlspecialchars($this->doc->issueCommand(
01694                         '&cmd['.$table.']['.$rec_on['uid'].'][version][action]=swap'.
01695                         '&cmd['.$table.']['.$rec_on['uid'].'][version][swapWith]='.$rec_off['uid']
01696                         )).'" title="' . $GLOBALS['LANG']->getLL('publish', TRUE) . '">'.
01697                     t3lib_iconWorks::getSpriteIcon('actions-version-swap-version') .
01698                 '</a>';
01699             if ($GLOBALS['BE_USER']->workspaceSwapAccess()) {
01700                 $actionLinks.=
01701                     '<a href="'.htmlspecialchars($this->doc->issueCommand(
01702                             '&cmd['.$table.']['.$rec_on['uid'].'][version][action]=swap'.
01703                             '&cmd['.$table.']['.$rec_on['uid'].'][version][swapWith]='.$rec_off['uid'].
01704                             '&cmd['.$table.']['.$rec_on['uid'].'][version][swapIntoWS]=1'
01705                             )).'" title="' . $GLOBALS['LANG']->getLL('swap', TRUE) . '">'.
01706                         t3lib_iconWorks::getSpriteIcon('actions-version-swap-workspace') .
01707                     '</a>';
01708             }
01709         }
01710 
01711         if (!$GLOBALS['BE_USER']->workspaceCannotEditOfflineVersion($table,$rec_off))   {
01712                 // Release
01713             $actionLinks.=
01714                 '<a href="'.htmlspecialchars($this->doc->issueCommand('&cmd['.$table.']['.$rec_off['uid'].'][version][action]=clearWSID')).'" onclick="return confirm(\'' . $GLOBALS['LANG']->getLL('removeFromWorkspace', TRUE) . '?\');" title="' . $GLOBALS['LANG']->getLL('removeFromWorkspace', TRUE) . '">'.
01715                     t3lib_iconWorks::getSpriteIcon('actions-version-document-remove') .
01716                 '</a>';
01717 
01718                 // Edit
01719             if ($table==='pages' && $vType!=='element') {
01720                 $tempUid = ($vType==='branch' || $GLOBALS['BE_USER']->workspace===0 ? $rec_off['uid'] : $rec_on['uid']);
01721                 $actionLinks.=
01722                     '<a href="#" onclick="top.loadEditId('.$tempUid.');top.goToModule(\''.$this->pageModule.'\'); return false;" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_user_ws.xml:img_title_edit_page', TRUE) . '">'.
01723                         t3lib_iconWorks::getSpriteIcon('actions-version-page-open') .
01724                     '</a>';
01725             } else {
01726                 $params = '&edit['.$table.']['.$rec_off['uid'].']=edit';
01727                 $actionLinks.=
01728                     '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick($params,$this->doc->backPath)).'" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_user_ws.xml:img_title_edit_element', TRUE). '">'.
01729                         t3lib_iconWorks::getSpriteIcon('actions-document-open') .
01730                     '</a>';
01731             }
01732         }
01733 
01734             // History/Log
01735         $actionLinks.=
01736             '<a href="'.htmlspecialchars($this->doc->backPath.'show_rechis.php?element='.rawurlencode($table.':'.$rec_off['uid']).'&returnUrl='.rawurlencode($this->REQUEST_URI)).'" title="' . $GLOBALS['LANG']->getLL('showLog', TRUE) . '">'.
01737                 t3lib_iconWorks::getSpriteIcon('actions-document-history-open') .
01738             '</a>';
01739 
01740             // View
01741         if ($table==='pages')   {
01742             $tempUid = ($vType==='branch' || $GLOBALS['BE_USER']->workspace===0 ? $rec_off['uid'] : $rec_on['uid']);
01743             $actionLinks.=
01744                 '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($tempUid,$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($tempUid))).'">'.
01745                     t3lib_iconWorks::getSpriteIcon('actions-document-view') .
01746                 '</a>';
01747         }
01748 
01749         return $actionLinks;
01750     }
01751 
01752     /**
01753      * Links to publishing etc of a version
01754      *
01755      * @param   string      Table name
01756      * @param   array       Record
01757      * @param   integer     The uid of the online version of $uid. If zero it means we are drawing a row for the online version itself while a value means we are drawing display for an offline version.
01758      * @return  string      HTML content, mainly link tags and images.
01759      */
01760     function displayWorkspaceOverview_commandLinksSub($table,$rec,$origId)  {
01761         $uid = $rec['uid'];
01762         if ($origId || $GLOBALS['BE_USER']->workspace===0)  {
01763             if (!$GLOBALS['BE_USER']->workspaceCannotEditRecord($table,$rec))   {
01764                     // Edit
01765                 if ($table==='pages')   {
01766                     $actionLinks.=
01767                         '<a href="#" onclick="top.loadEditId('.$uid.');top.goToModule(\''.$this->pageModule.'\'); return false;" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_user_ws.xml:img_title_edit_page', TRUE) . '">'.
01768                             t3lib_iconWorks::getSpriteIcon('apps-version-page-open') .
01769                         '</a>';
01770                 } else {
01771                     $params = '&edit['.$table.']['.$uid.']=edit';
01772                     $actionLinks.=
01773                         '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick($params,$this->doc->backPath)).'" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_user_ws.xml:img_title_edit_element', TRUE) . '">'.
01774                             t3lib_iconWorks::getSpriteIcon('actions-document-open') .
01775                         '</a>';
01776                 }
01777             }
01778 
01779                 // History/Log
01780             $actionLinks.=
01781                 '<a href="'.htmlspecialchars($this->doc->backPath.'show_rechis.php?element='.rawurlencode($table.':'.$uid).'&returnUrl='.rawurlencode($this->REQUEST_URI)).'" title="' . $GLOBALS['LANG']->getLL('showLog', TRUE) . '">'.
01782                     t3lib_iconWorks::getSpriteIcon('actions-document-history-open') .
01783                 '</a>';
01784         }
01785 
01786             // View
01787         if ($table==='pages')   {
01788             $actionLinks.=
01789                 '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($uid,$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($uid))).'">'.
01790                     t3lib_iconWorks::getSpriteIcon('actions-document-view') .
01791                 '</a>';
01792         }
01793 
01794         return $actionLinks;
01795     }
01796 
01797 
01798 
01799 
01800 
01801 
01802 
01803 
01804 
01805     /**********************************
01806      *
01807      * Processing
01808      *
01809      **********************************/
01810 
01811     /**
01812      * Will publish workspace if buttons are pressed
01813      *
01814      * @return  void
01815      */
01816     function publishAction()    {
01817 
01818             // If "Publish" or "Swap" buttons are pressed:
01819         if (t3lib_div::_POST('_publish') || t3lib_div::_POST('_swap'))  {
01820 
01821             if ($this->table==='pages') {   // Making sure ->uid is a page ID!
01822                     // Initialize workspace object and request all pending versions:
01823                 $wslibObj = t3lib_div::makeInstance('wslib');
01824                 $cmd = $wslibObj->getCmdArrayForPublishWS($GLOBALS['BE_USER']->workspace, t3lib_div::_POST('_swap'),$this->uid);
01825 
01826                     // Execute the commands:
01827                 $tce = t3lib_div::makeInstance('t3lib_TCEmain');
01828                 $tce->stripslashes_values = 0;
01829                 $tce->start(array(), $cmd);
01830                 $tce->process_cmdmap();
01831 
01832                 t3lib_BEfunc::setUpdateSignal('updatePageTree');
01833 
01834                 return $tce->errorLog;
01835             }
01836         }
01837     }
01838 }
01839 
01840 
01841 
01842 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/version/cm1/index.php'])) {
01843     include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/version/cm1/index.php']);
01844 }
01845 
01846 
01847 
01848 
01849 // Make instance:
01850 $SOBE = t3lib_div::makeInstance('tx_version_cm1');
01851 $SOBE->init();
01852 
01853 
01854 $SOBE->main();
01855 $SOBE->printContent();
01856 
01857 ?>