TYPO3 API  SVNRelease
class.wslib_gui.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003  *  Copyright notice
00004  *
00005  *  (c) 2005-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  *  A copy is found in the textfile GPL.txt and important notices to the license
00017  *  from the author is found in LICENSE.txt distributed with these scripts.
00018  *
00019  *
00020  *  This script is distributed in the hope that it will be useful,
00021  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  *  GNU General Public License for more details.
00024  *
00025  *  This copyright notice MUST APPEAR in all copies of the script!
00026  ***************************************************************/
00027 /**
00028  * Library with Workspace GUI related functionality. It is used by main workspace
00029  * module but also can be used from extensions. Originally 99.9%% of the code
00030  * was written by Kasper and only transfered here by Dmitry.
00031  *
00032  * $Id: class.wslib_gui.php 10222 2011-01-21 18:22:24Z tolleiv $
00033  *
00034  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00035  * @author  Dmitry Dulepov <dmitry@typo3.org>
00036  */
00037 /**
00038  * [CLASS/FUNCTION INDEX of SCRIPT]
00039  *
00040  *
00041  *
00042  *   84: class wslib_gui
00043  *
00044  *              SECTION: Public functions
00045  *  128:     function getWorkspaceOverview(&$doc, $wsid = null, $filter = 0, $pageId = -1)
00046  *  192:     function hlSubelements(origId, verId, over, diffLayer)
00047  *
00048  *              SECTION: Private functions (do not use outside of this class!)
00049  *  224:     function initVars()
00050  *  253:     function displayWorkspaceOverview_setInPageArray(&$pArray, $rlArr, $table, $row)
00051  *  284:     function markupNewOriginals()
00052  *  309:     function displayWorkspaceOverview_list($pArray, $tableRows=array(), $c=0, $warnAboutVersions=FALSE)
00053  *  504:     function displayWorkspaceOverview_pageTreeIconTitle($pageUid, $title, $indentCount)
00054  *  518:     function formatVerId($verId)
00055  *  529:     function formatWorkspace($wsid)
00056  *  559:     function createDiffView($table, $diff_1_record, $diff_2_record)
00057  *  676:     function versionsInOtherWS($table, $uid)
00058  *  705:     function showStageChangeLog($table,$id,$stageCommands)
00059  *  757:     function displayWorkspaceOverview_commandLinks($table,&$rec_on,&$rec_off,$vType)
00060  *  830:     function formatCount($count)
00061  *  860:     function subElements($uid,$treeLevel,$origId=0)
00062  *  963:     function subElements_getNonPageRecords($tN, $uid, &$recList)
00063  *  993:     function subElements_renderItem(&$tCell,$tN,$uid,$rec,$origId,$iconMode,$HTMLdata)
00064  * 1066:     function displayWorkspaceOverview_commandLinksSub($table,$rec,$origId)
00065  * 1113:     function displayWorkspaceOverview_stageCmd($table,&$rec_off)
00066  *
00067  * TOTAL FUNCTIONS: 19
00068  * (This index is automatically created/updated by the extension "extdeveval")
00069  *
00070  */
00071 
00072 require_once('class.wslib.php');
00073 $LANG->includeLLFile('EXT:lang/locallang_mod_user_ws.xml');
00074 $LANG->includeLLFile('EXT:lang/locallang_misc.xml');
00075 
00076 /**
00077  * Library with Workspace GUI related functionality. It is used by main workspace
00078  * module but also can be used from extensions. Originally 99.9%% of the code
00079  * was written by Kasper and only transfered here by Dmitry.
00080  *
00081  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00082  * @author  Dmitry Dulepov <dmitry@typo3.org>
00083  * @package TYPO3
00084  * @subpackage core
00085  */
00086 class wslib_gui {
00087 
00088     // Static:
00089     var $pageTreeIndent = 8;
00090     var $pageTreeIndent_titleLgd = 30;
00091 
00092     // Options
00093     var $diff = false;
00094     var $expandSubElements = false;
00095     var $alwaysDisplayHeader = false;
00096 
00097     // Internal
00098     var $showWorkspaceCol = 0;
00099     var $doc;
00100     var $formatWorkspace_cache = array();
00101     var $targets = array();                     // Accumulation of online targets.
00102     var $be_user_Array = array();
00103     var $pageModule = '';
00104     var $formatCount_cache = array();
00105     var $stageIndex = array();
00106     var $addHlSubelementsScript = false;
00107 
00108     /*********************************
00109      *
00110      * Public functions
00111      *
00112      *********************************/
00113 
00114     /**
00115      * Creates HTML to display workspace overview. Can be used to display overview for all possible records or only for single page.
00116      *
00117      * The following code is <strong>required</strong> in BE module when this function is used:
00118      * <code>
00119      *  $this->doc->getContextMenuCode();
00120      * </code>
00121      * or click-menu will not be generated properly!
00122      *
00123      * @param   object      $doc    Document (to use for formatting)
00124      * @param   int     $wsid   Workspace ID, If <code>null</code>, the value is obtained from current BE user
00125      * @param   int     $filter If 0, than no filtering, if 10 than select for publishing, otherwise stage value
00126      * @param   int     $pageId If greater than zero, than it is UID of page in LIVE workspaces to select records for
00127      * @return  string      Generated HTML
00128      */
00129     function getWorkspaceOverview(&$doc, $wsid = null, $filter = 0, $pageId = -1) {
00130         global  $LANG;
00131 
00132         // Setup
00133         $this->workspaceId = (!is_null($wsid) ? $wsid : $GLOBALS['BE_USER']->workspace);
00134         $this->showWorkspaceCol = $GLOBALS['BE_USER']->workspace == 0 && $this->workspaceId <= -98;
00135         $this->doc = $doc;
00136         $this->initVars();
00137 
00138         // Initialize workspace object and request all pending versions:
00139         $wslibObj = t3lib_div::makeInstance('wslib');
00140 
00141         // Selecting ALL versions belonging to the workspace:
00142         $versions = $wslibObj->selectVersionsInWorkspace($this->workspaceId, $filter, -99, $pageId);
00143 
00144         // Traverse versions and build page-display array:
00145         $pArray = array();
00146         $wmArray = array(); // is page in web mount?
00147         $rlArray = array(); // root line of page
00148         $pagePermsClause = $GLOBALS['BE_USER']->getPagePermsClause(1);
00149         foreach($versions as $table => $records)    {
00150             if (is_array($records)) {
00151                 foreach($records as $rec)   {
00152                     $pageIdField = $table==='pages' ? 't3ver_oid' : 'realpid';
00153                     $recPageId = $rec[$pageIdField];
00154                     if (!isset($wmArray[$recPageId]))   {
00155                         $wmArray[$recPageId] = $GLOBALS['BE_USER']->isInWebMount($recPageId,$pagePermsClause);
00156                     }
00157                     if ($wmArray[$recPageId])   {
00158                         if (!isset($rlArray[$recPageId]))   {
00159                             $rlArray[$recPageId] = t3lib_BEfunc::BEgetRootLine($recPageId, 'AND 1=1');
00160                         }
00161                         $this->displayWorkspaceOverview_setInPageArray(
00162                             $pArray,
00163                             $rlArray[$recPageId],
00164                             $table,
00165                             $rec
00166                         );
00167                     }
00168                 }
00169             }
00170         }
00171 
00172             // Page-browser:
00173         $resultsPerPage = 50;
00174         $pointer = t3lib_div::_GP('browsePointer');
00175         $browseStat = $this->cropWorkspaceOverview_list($pArray,$pointer,$resultsPerPage);
00176         $browse = '';
00177         $browse .= '<h3>Showing ' . $browseStat['begin'] . ' to ' . ($browseStat['end'] ? $browseStat['end'] . ' out of ' . $browseStat['allItems'] : $browseStat['allItems']) . ' versions:</h3>';
00178         if (!($browseStat['begin']==1 && !$browseStat['end']))  {
00179             for($a=0;$a<ceil($browseStat['allItems']/$resultsPerPage);$a++) {
00180                 $browse.=($a==(int)$pointer?'<strong>':'').'<a href="'.htmlspecialchars('index.php?browsePointer='.rawurlencode($a)).'">['.($a+1).']</a>'.($a==(int)$pointer?'</strong>':'').' ';
00181             }
00182         }
00183 
00184         $workspaceOverviewList = $this->displayWorkspaceOverview_list($pArray);
00185         if ($workspaceOverviewList || $this->alwaysDisplayHeader) {
00186             // Make header of overview:
00187             $tableRows = array();
00188             $tableHeader = '
00189                 <tr class="t3-row-header">
00190                     <td nowrap="nowrap" width="100">' . $LANG->getLL('label_pagetree') . '</td>
00191                     <td nowrap="nowrap" colspan="2">' . $LANG->getLL('label_live_version') . '</td>
00192                     <td nowrap="nowrap" colspan="2">' . $LANG->getLL('label_draft_versions') . '</td>
00193                     <td nowrap="nowrap">' . $LANG->getLL('label_stage') . '</td>
00194                     <td nowrap="nowrap">' . $LANG->getLL('label_publish') . '</td>
00195                     <td><select name="_with_selected_do" onchange="if (confirm(\'' . $LANG->getLL('submit_apply_action_on_selected_elements') . '\')) {document.forms[0].submit();}">
00196                         <option value="_">' . $LANG->getLL('label_doaction_default') . '</option>';
00197 
00198             if ($this->publishAccess && !($GLOBALS['BE_USER']->workspaceRec['publish_access'] & 1)) {
00199                 $tableHeader .= '<option value="publish">' . $LANG->getLL('label_doaction_publish') . '</option>';
00200                 if ($GLOBALS['BE_USER']->workspaceSwapAccess()) {
00201                     $tableHeader .= '<option value="swap">' . $LANG->getLL('label_doaction_swap') . '</option>';
00202                 }
00203             }
00204             if ($GLOBALS['BE_USER']->workspace !== 0) {
00205                 $tableHeader .= '<option value="release">' . $LANG->getLL('label_doaction_release') . '</option>';
00206             }
00207             $tableHeader .= $GLOBALS['BE_USER']->workspaceCheckStageForCurrent('-1') ? '<option value="stage_-1">' . $LANG->getLL('label_doaction_stage_reject') . '</option>' : '';
00208             $tableHeader .= $GLOBALS['BE_USER']->workspaceCheckStageForCurrent('0') ? '<option value="stage_0">' . $LANG->getLL('label_doaction_stage_editing') . '</option>' : '';
00209             $tableHeader .= $GLOBALS['BE_USER']->workspaceCheckStageForCurrent('1') ? '<option value="stage_1">' . $LANG->getLL('label_doaction_stage_review') . '</option>' : '';
00210             $tableHeader .= $GLOBALS['BE_USER']->workspaceCheckStageForCurrent('10') ? '<option value="stage_10">' . $LANG->getLL('label_doaction_stage_publish') . '</option>' : '';
00211 
00212             $tableHeader .= '<option value="flush">' . $LANG->getLL('label_doaction_flush') . '</option>
00213                     </select></td>
00214                     <td>' . $LANG->getLL('label_lifecycle') . '</td>
00215                     '.($this->showWorkspaceCol ? '<td>' . $LANG->getLL('label_workspace') . '</td>' : '').'
00216                 </tr>';
00217             $tableRows[] = $tableHeader;
00218 
00219             // Add lines from overview:
00220             $tableRows = array_merge($tableRows, $workspaceOverviewList);
00221 
00222             $table = '<table border="0" cellpadding="0" cellspacing="0" id="t3-user-ws-wsoverview-table" class="typo3-dblist">' . implode('', $tableRows) . '</table>';
00223 
00224             // script
00225             if ($this->addHlSubelementsScript && !strstr($this->doc->JScode, 'function hlSubelements(')) {
00226                 $table = $this->doc->wrapScriptTags('
00227                     function hlSubelements(origId, verId, over, diffLayer)  {
00228                         if (over)   {
00229                             document.getElementById(\'orig_\'+origId).attributes.getNamedItem("class").nodeValue = \'typo3-ver-hl\';
00230                             document.getElementById(\'ver_\'+verId).attributes.getNamedItem("class").nodeValue = \'typo3-ver-hl\';
00231                             if (diffLayer)  {
00232                                 document.getElementById(\'diff_\'+verId).style.visibility = \'visible\';
00233                             }
00234                         } else {
00235                             document.getElementById(\'orig_\'+origId).attributes.getNamedItem("class").nodeValue = \'typo3-ver\';
00236                             document.getElementById(\'ver_\'+verId).attributes.getNamedItem("class").nodeValue = \'typo3-ver\';
00237                             if (diffLayer)  {
00238                                 document.getElementById(\'diff_\'+verId).style.visibility = \'hidden\';
00239                             }
00240                         }
00241                     }
00242                 ') . $table;
00243             }
00244 
00245             return $browse . $table . $this->markupNewOriginals();
00246         }
00247         return '';
00248     }
00249 
00250     /*********************************
00251      *
00252      * Private functions (do not use outside of this class!)
00253      *
00254      *********************************/
00255 
00256     /**
00257      * Initializes several class variables
00258      *
00259      * @return  void
00260      */
00261     function initVars() {
00262         // Init users
00263         $be_group_Array = t3lib_BEfunc::getListGroupNames('title,uid');
00264         $groupArray = array_keys($be_group_Array);
00265         // Need 'admin' field for t3lib_iconWorks::getIconImage()
00266         $this->be_user_Array = t3lib_BEfunc::getUserNames('username,usergroup,usergroup_cached_list,uid,admin,workspace_perms');
00267         if (!$GLOBALS['BE_USER']->isAdmin()) {
00268             $this->be_user_Array = t3lib_BEfunc::blindUserNames($this->be_user_Array,$groupArray,1);
00269         }
00270 
00271         // If another page module was specified, replace the default Page module with the new one
00272         $newPageModule = trim($GLOBALS['BE_USER']->getTSConfigVal('options.overridePageModule'));
00273         $this->pageModule = t3lib_BEfunc::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
00274 
00275         // Setting publish access permission for workspace:
00276         $this->publishAccess = $GLOBALS['BE_USER']->workspacePublishAccess($GLOBALS['BE_USER']->workspace); // FIXME Should be $this->workspaceId here?
00277     }
00278 
00279     /**
00280      * Building up of the $pArray variable which is a hierarchical storage of table-rows arranged according to the level in the rootline the element was found
00281      * (Internal)
00282      * Made for recursive calling
00283      *
00284      * @param   array       Array that is built up with the page tree structure
00285      * @param   array       Root line for element (table / row); The element is stored in pArray according to this root line.
00286      * @param   string      Table name
00287      * @param   array       Table row
00288      * @return  void        $pArray is passed by reference and modified internally
00289      */
00290     function displayWorkspaceOverview_setInPageArray(&$pArray, $rlArr, $table, $row)    {
00291         // Initialize:
00292         ksort($rlArr);
00293         reset($rlArr);
00294         if (!$rlArr[0]['uid']) {
00295             array_shift($rlArr);
00296         }
00297 
00298         // Get and remove first element in root line:
00299         $cEl = current($rlArr);
00300         $pUid = $cEl['t3ver_oid'] ? $cEl['t3ver_oid'] : $cEl['uid'];        // Done to pile up "false versions" in the right branch...
00301 
00302         $pArray[$pUid] = $cEl['title'];
00303         array_shift($rlArr);
00304 
00305         // If there are elements left in the root line, call this function recursively (to build $pArray in depth)
00306         if (count($rlArr))  {
00307             if (!isset($pArray[$pUid.'.'])) {
00308                 $pArray[$pUid.'.'] = array();
00309             }
00310             $this->displayWorkspaceOverview_setInPageArray($pArray[$pUid.'.'], $rlArr, $table, $row);
00311         } else {    // If this was the last element, set the value:
00312             $pArray[$pUid.'_'][$table][$row['t3ver_oid']][] = $row;
00313         }
00314     }
00315 
00316     /**
00317      * JavaScript code to mark up new records that are online (in sub element lists)
00318      *
00319      * @return  string      HTML javascript section
00320      */
00321     function markupNewOriginals()   {
00322 
00323         if (count($this->targets))  {
00324             $scriptCode = '';
00325             foreach($this->targets as $key => $rec) {
00326                 $scriptCode.='
00327                     document.getElementById(\''.$key.'\').attributes.getNamedItem("class").nodeValue = \'typo3-ver-new\';
00328                 ';
00329             }
00330 
00331             return $this->doc->wrapScriptTags($scriptCode);
00332         }
00333     }
00334 
00335 
00336     /**
00337      * Rendering the content for the publish / review overview:
00338      * (Made for internal recursive calling)
00339      *
00340      * @param   array       Hierarchical storage of the elements to display (see displayWorkspaceOverview() / displayWorkspaceOverview_setInPageArray())
00341      * @param   array       Existing array of table rows to add to
00342      * @param   array       Depth counter
00343      * @param   boolean     If set, a warning is shown if versions are found (internal flag)
00344      * @return  array       Table rows, see displayWorkspaceOverview()
00345      */
00346     function displayWorkspaceOverview_list($pArray, $tableRows=array(), $c=0, $warnAboutVersions=FALSE) {
00347         global $TCA, $LANG;
00348 
00349         // Initialize:
00350         $fullColSpan = $this->showWorkspaceCol ? 10 : 9;
00351 
00352         // Traverse $pArray
00353         if (is_array($pArray))  {
00354             foreach($pArray as $k => $v)    {
00355                 if (t3lib_div::testInt($k)) {
00356 
00357                     // If there are elements on this level, output a divider row which just creates a little visual space.
00358                     if (is_array($pArray[$k.'_']))  {
00359                         $tableRows[] = '
00360                             <tr>
00361                                 <td colspan="'.$fullColSpan.'"><img src="clear.gif" width="1" height="3" alt="" /></td>
00362                             </tr>';
00363                     }
00364 
00365                     // Printing a level from the page tree with no additional content:
00366                     // If there are NO elements on this level OR if there are NO pages on a level with elements, then show page tree icon and title (otherwise it is shown with the display of the elements)
00367                     if (!is_array($pArray[$k.'_']) || !is_array($pArray[$k.'_']['pages']))  {
00368                         $tableRows[] = '
00369                             <tr class="bgColor4-20">
00370                                 <td nowrap="nowrap" colspan="'.$fullColSpan.'">'.
00371                                 $this->displayWorkspaceOverview_pageTreeIconTitle($k,$pArray[$k],$c).
00372                                 '</td>
00373                             </tr>';
00374                     }
00375 
00376                     // If there ARE elements on this level, print them:
00377                     $warnAboutVersions_next = $warnAboutVersions;
00378                     $warnAboutVersions_nonPages = FALSE;
00379                     $warnAboutVersions_page = FALSE;
00380                     if (is_array($pArray[$k.'_']))  {
00381                         foreach($pArray[$k.'_'] as $table => $oidArray) {
00382                             foreach($oidArray as $oid => $recs) {
00383 
00384                                 // Get CURRENT online record and icon based on "t3ver_oid":
00385                                 $rec_on = t3lib_BEfunc::getRecord($table,$oid);
00386                                 $icon = t3lib_iconWorks::getIconImage($table, $rec_on, $this->doc->backPath,' align="top" title="'.t3lib_BEfunc::getRecordIconAltText($rec_on,$table).'"');
00387                                 if ($GLOBALS['BE_USER']->workspace===0) {   // Only edit online records if in ONLINE workspace:
00388                                     $icon = $this->doc->wrapClickMenuOnIcon($icon, $table, $rec_on['uid'], 2, '', '+edit,view,info,delete');
00389                                 }
00390 
00391                                 // MAIN CELL / Online version display:
00392                                 // Create the main cells which will span over the number of versions there is. If the table is "pages" then it will show the page tree icon and title (which was not shown by the code above)
00393                                 $verLinkUrl = t3lib_extMgm::isLoaded('version') && $TCA[$table]['ctrl']['versioningWS'];
00394                                 $origElement = $icon.
00395                                 ($verLinkUrl ? '<a href="'.htmlspecialchars($this->doc->backPath.t3lib_extMgm::extRelPath('version').'cm1/index.php?table='.$table.'&uid='.$rec_on['uid']).'">' : '').
00396                                                 t3lib_BEfunc::getRecordTitle($table,$rec_on,TRUE).
00397                                                 ($verLinkUrl ? '</a>' : '');
00398                                 $mainCell_rowSpan = count($recs)>1 ? ' rowspan="'.count($recs).'"' : '';
00399                                 $mainCell = $table==='pages' ? '
00400                                             <td class="bgColor4-20" nowrap="nowrap"'.$mainCell_rowSpan.'>'.
00401                                             $this->displayWorkspaceOverview_pageTreeIconTitle($k,$pArray[$k],$c).
00402                                             '</td>' : '
00403                                             <td class="bgColor"'.$mainCell_rowSpan.'></td>';
00404                                 $mainCell.= '
00405                                             <td align="center"'.$mainCell_rowSpan.'>'.$this->formatVerId($rec_on['t3ver_id']).'</td>
00406                                             <td nowrap="nowrap"'.$mainCell_rowSpan.'>'.
00407                                 $origElement.
00408                                 '###SUB_ELEMENTS###'.   // For substitution with sub-elements, if any.
00409                                 '</td>';
00410 
00411                                 // Offline versions display:
00412                                 // Traverse the versions of the element
00413                                 foreach($recs as $rec)  {
00414 
00415                                     // Get the offline version record:
00416                                     $rec_off = t3lib_BEfunc::getRecord($table,$rec['uid']);
00417 
00418                                     // Prepare swap-mode values:
00419                                     if ($table==='pages' && $rec_off['t3ver_swapmode']!=-1) {
00420                                         if ($rec_off['t3ver_swapmode']>0)   {
00421                                             $vType = 'branch';  // Do not translate!
00422                                         } else {
00423                                             $vType = 'page';    // Do not translate!
00424                                         }
00425                                     } else {
00426                                         $vType = 'element'; // Do not translate!
00427                                     }
00428 
00429                                     // Get icon:
00430                                     $icon = t3lib_iconWorks::getIconImage($table, $rec_off, $this->doc->backPath, ' align="top" title="'.t3lib_BEfunc::getRecordIconAltText($rec_off,$table).'"');
00431                                     $tempUid = ($table != 'pages' || $vType==='branch' || $GLOBALS['BE_USER']->workspace == 0 ? $rec_off['uid'] : $rec_on['uid']);
00432                                     $icon = $this->doc->wrapClickMenuOnIcon($icon, $table, $tempUid, 2, '', '+edit,' . ($table == 'pages' ? 'view,info,' : '') . 'delete');
00433 
00434                                     // Prepare diff-code:
00435                                     if ($this->diff)    {
00436                                         $diffCode = '';
00437                                         list($diffHTML,$diffPct) = $this->createDiffView($table, $rec_off, $rec_on);
00438                                         if ($rec_on['t3ver_state']==1)  {   // New record:
00439                                             $diffCode.= $this->doc->icons(1) . $LANG->getLL('label_newrecord') . '<br />';
00440                                             $diffCode.= $diffHTML;
00441                                         } elseif ($rec_off['t3ver_state']==2)   {
00442                                             $diffCode.= $this->doc->icons(2) . $LANG->getLL('label_deletedrecord') . '<br/>';
00443                                         } elseif ($rec_on['t3ver_state']==3)    {
00444                                             $diffCode.= $this->doc->icons(1) . $LANG->getLL('label_moveto_placeholder') . '<br/>';
00445                                         } elseif ($rec_off['t3ver_state']==4)   {
00446                                             $diffCode.= $this->doc->icons(1) . $LANG->getLL('label_moveto_pointer') . '<br/>';
00447                                         } else {
00448                                             $diffCode .= ($diffPct < 0 ? $LANG->getLL('label_notapplicable') :
00449                                                 ($diffPct ? sprintf($LANG->getLL('label_percentChange'), $diffPct) : ''));
00450                                             $diffCode.= $diffHTML;
00451                                         }
00452 
00453                                     } else $diffCode = '';
00454 
00455                                     switch($vType) {
00456                                         case 'element':
00457                                             $swapLabel = ' ['.$LANG->getLL('label_element').']';
00458                                             $swapClass = 'ver-element'; // Do not translate!
00459                                             $warnAboutVersions_nonPages = $warnAboutVersions_page;  // Setting this if sub elements are found with a page+content (must be rendered prior to this of course!)
00460                                             break;
00461                                         case 'page':
00462                                             $swapLabel = ' ['.$LANG->getLL('label_page').']';
00463                                             $swapClass = 'ver-page';    // Do not translate!
00464                                             $warnAboutVersions_page = !$this->showWorkspaceCol;     // This value is true only if multiple workspaces are shown and we need the opposite here.
00465                                             break;
00466                                         case 'branch':
00467                                             $swapLabel = ' ['.$LANG->getLL('label_branch').']';
00468                                             $swapClass = 'ver-branch';  // Do not translate!
00469                                             $warnAboutVersions_next = !$this->showWorkspaceCol;     // This value is true only if multiple workspaces are shown and we need the opposite here.
00470                                             break;
00471                                     }
00472 
00473                                     // Modify main cell based on first version shown:
00474                                     $subElements = array();
00475                                     if ($table==='pages' && $rec_off['t3ver_swapmode']!=-1 && $mainCell)    {   // For "Page" and "Branch" swap modes where $mainCell is still carrying content (only first version)
00476                                         $subElements['on'] = $this->subElements($rec_on['uid'], $rec_off['t3ver_swapmode']);
00477                                         $subElements['off'] = $this->subElements($rec_off['uid'],$rec_off['t3ver_swapmode'],$rec_on['uid']);
00478                                     }
00479                                     $mainCell = str_replace('###SUB_ELEMENTS###', $subElements['on'], $mainCell);
00480 
00481                                     // Create version element:
00482                                     $versionsInOtherWS = $this->versionsInOtherWS($table, $rec_on['uid']);
00483                                     $versionsInOtherWSWarning = $versionsInOtherWS && $GLOBALS['BE_USER']->workspace !== 0 ? '<br />' . $this->doc->icons(2) . $LANG->getLL('label_otherversions') . ' ' . $versionsInOtherWS : '';
00484                                     $multipleWarning = (!$mainCell && $GLOBALS['BE_USER']->workspace !==0 ? '<br />' . $this->doc->icons(3) . '<strong>' . $LANG->getLL('label_multipleversions') . '</strong>' : '');
00485                                     $verWarning = $warnAboutVersions || ($warnAboutVersions_nonPages && $GLOBALS['TCA'][$table]['ctrl']['versioning_followPages']) ? '<br />' . $this->doc->icons(3) . '<strong>' . $LANG->getLL('label_nestedversions') . '</strong>' : '';
00486                                     $verElement = $icon.
00487                                         '<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(t3lib_div::getIndpEnv('REQUEST_URI'))).'">'.
00488                                         t3lib_BEfunc::getRecordTitle($table,$rec_off,TRUE).
00489                                         '</a>'.
00490                                         $versionsInOtherWSWarning.
00491                                         $multipleWarning.
00492                                         $verWarning;
00493                                     if ($diffCode)  {
00494                                         $verElement = '
00495                                         <table border="0" cellpadding="0" cellspacing="0" class="ver-verElement">
00496                                             <tr>
00497                                                 <td nowrap="nowrap" width="180">'.$verElement.'&nbsp;&nbsp;</td>
00498                                                 <td class="c-diffCell">'.$diffCode.'</td>
00499                                             </tr>
00500                                         </table>';
00501                                     }
00502 
00503                                     // Create version cell:
00504                                     $verCell = '
00505                                             <td align="center">'.$this->formatVerId($rec_off['t3ver_id']).'</td>
00506                                             <td nowrap="nowrap">'.
00507                                     $verElement.
00508                                     $subElements['off'].
00509                                     '</td>';
00510 
00511                                     // Compile table row:
00512                                     $tableRows[] = '
00513                                         <tr class="bgColor4">
00514                                             '.$mainCell.$verCell.'
00515                                             <td nowrap="nowrap">'.$this->showStageChangeLog($table,$rec_off['uid'],$this->displayWorkspaceOverview_stageCmd($table,$rec_off)).'</td>
00516                                             <td nowrap="nowrap" class="'.$swapClass.'">'.
00517                                     $this->displayWorkspaceOverview_commandLinks($table,$rec_on,$rec_off,$vType).
00518                                     htmlspecialchars($swapLabel).
00519                                     '</td>
00520                                             <td nowrap="nowrap" align="center"><input type="checkbox" name="items['.$table.':'.$rec_off['uid'].']" id="items['.$table.':'.$rec_off['uid'].']" value="1"/></td>
00521                                             <td nowrap="nowrap">'.htmlspecialchars($this->formatCount($rec_off['t3ver_count'])).'</td>'.        // Lifecycle
00522                                     ($this->showWorkspaceCol ? '
00523                                             <td nowrap="nowrap">'.htmlspecialchars($this->formatWorkspace($rec_off['t3ver_wsid'])).'</td>' : '').'
00524                                         </tr>';
00525 
00526                                     // Reset the main cell:
00527                                     $mainCell = '';
00528                                 }
00529                             }
00530                         }
00531                     }
00532                     // Call recursively for sub-rows:
00533                     $tableRows = $this->displayWorkspaceOverview_list($pArray[$k.'.'], $tableRows, $c+1, $warnAboutVersions_next);
00534                 }
00535             }
00536         }
00537         return $tableRows;
00538     }
00539 
00540     /**
00541      * Filtering out items in pArray according to pointer and result-per-page setting
00542      *
00543      * @param   array       Hierarchical storage of the elements to display (see displayWorkspaceOverview() / displayWorkspaceOverview_setInPageArray())
00544      * @return  array       Returns statistics about the pointer state.
00545      */
00546     function cropWorkspaceOverview_list(&$pArray,$pointer=0,$resPerPage=50,$stat=array())   {
00547 
00548             // Traverse $pArray
00549         if (is_array($pArray))  {
00550             foreach($pArray as $k => $v)    {
00551                 if (t3lib_div::testInt($k)) {
00552 
00553                     if (is_array($pArray[$k.'_']))  {
00554                         foreach($pArray[$k.'_'] as $table => $oidArray) {
00555                             foreach($oidArray as $oid => $recs) {
00556 
00557                                     // Check, if the item count has reached the point where we want to set the in-point.
00558                                 $beginWasSet = FALSE;
00559                                 if (!isset($stat['begin']) && (int)$stat['allItems'] >= $pointer*$resPerPage)   {
00560                                     $stat['begin']=(int)$stat['allItems']+1;
00561                                     $beginWasSet = TRUE;
00562                                 }
00563 
00564                                     // If in-point is not set, unset the previous items.
00565                                 if (!isset($stat['begin'])) {
00566                                     unset($pArray[$k.'_'][$table][$oid]);
00567                                 }
00568 
00569                                     // Increase counter:
00570                                 $stat['allItems']+=count($recs);
00571 
00572                                     // Check if end-point is reached:
00573                                 if (!$beginWasSet && !isset($stat['end']) && $stat['allItems'] > ($pointer+1)*$resPerPage)  {
00574                                     $stat['end']=$stat['allItems']-1;
00575                                 }
00576 
00577                                     // If end-point is reached, unset following items.
00578                                 if (isset($stat['end']))    {
00579                                     unset($pArray[$k.'_'][$table][$oid]);
00580                                 }
00581                             }
00582 
00583                                 // Clean-up if no more items:
00584                             if (!count($pArray[$k.'_'][$table]))    {
00585                                 unset($pArray[$k.'_'][$table]);
00586                             }
00587                         }
00588 
00589                             // Clean-up if no more items:
00590                         if (!count($pArray[$k.'_']))    {
00591                             unset($pArray[$k.'_']);
00592                         }
00593                     }
00594 
00595                         // Call recursively for sub-rows:
00596                     if (is_array($pArray[$k.'.']))  {
00597                         $stat = $this->cropWorkspaceOverview_list($pArray[$k.'.'],$pointer,$resPerPage,$stat);
00598                     }
00599                 }
00600             }
00601         }
00602         return $stat;
00603     }
00604 
00605     /**
00606      * Create indentation, icon and title for the page tree identification for the list.
00607      *
00608      * @param   integer     Page UID (record will be looked up again)
00609      * @param   string      Page title
00610      * @param   integer     Depth counter from displayWorkspaceOverview_list() used to indent the icon and title
00611      * @return  string      HTML content
00612      */
00613     function displayWorkspaceOverview_pageTreeIconTitle($pageUid, $title, $indentCount) {
00614         $pRec = t3lib_BEfunc::getRecord('pages',$pageUid);
00615         return '<img src="clear.gif" width="1" height="1" hspace="'.($indentCount * $this->pageTreeIndent).'" align="top" alt="" />'.   // Indenting page tree
00616             t3lib_iconWorks::getSpriteIconForRecord('pages', $pRec, array('title'=> t3lib_BEfunc::getRecordIconAltText($pRec,'pages'))) .
00617             htmlspecialchars(t3lib_div::fixed_lgd_cs($title,$this->pageTreeIndent_titleLgd)).
00618             '&nbsp;&nbsp;';
00619     }
00620 
00621     /**
00622      * Formatting the version number for HTML output
00623      *
00624      * @param   integer     Version number
00625      * @return  string      Version number for output
00626      */
00627     function formatVerId($verId)    {
00628         return '1.'.$verId;
00629     }
00630 
00631 
00632     /**
00633      * Formatting workspace ID into a visual label
00634      *
00635      * @param   integer     Workspace ID
00636      * @return  string      Workspace title
00637      */
00638     function formatWorkspace($wsid) {
00639 
00640         // Render, if not cached:
00641         if (!isset($this->formatWorkspace_cache[$wsid]))    {
00642             switch($wsid)   {
00643                 case -1:
00644                     $this->formatWorkspace_cache[$wsid] = '[Draft]';
00645                     break;
00646                 case 0:
00647                     $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...
00648                     break;
00649                 default:
00650                     $titleRec = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('title', 'sys_workspace', 'uid=' . intval($wsid) . t3lib_BEfunc::deleteClause('sys_workspace'));
00651                     $this->formatWorkspace_cache[$wsid] = '['.$wsid.'] '.$titleRec['title'];
00652                     break;
00653             }
00654         }
00655 
00656         return $this->formatWorkspace_cache[$wsid];
00657     }
00658 
00659 
00660     /**
00661      * Create visual difference view of two records. Using t3lib_diff library
00662      *
00663      * @param   string      Table name
00664      * @param   array       New version record (green)
00665      * @param   array       Old version record (red)
00666      * @return  array       Array with two keys (0/1) with HTML content / percentage integer (if -1, then it means N/A) indicating amount of change
00667      */
00668     function createDiffView($table, $diff_1_record, $diff_2_record) {
00669         global $TCA, $LANG;
00670 
00671         // Initialize:
00672         $pctChange = 'N/A';
00673 
00674         // Check that records are arrays:
00675         if (is_array($diff_1_record) && is_array($diff_2_record))   {
00676 
00677             // Load full table description and initialize diff-object:
00678             t3lib_div::loadTCA($table);
00679             $t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff');
00680 
00681             // Add header row:
00682             $tRows = array();
00683             $tRows[] = '
00684                 <tr class="bgColor5 tableheader">
00685                     <td>' . $LANG->getLL('diffview_label_field_name') . '</td>
00686                     <td width="98%" nowrap="nowrap">' . $LANG->getLL('diffview_label_colored_diff_view') . '</td>
00687                 </tr>
00688             ';
00689 
00690             // Initialize variables to pick up string lengths in:
00691             $allStrLen = 0;
00692             $diffStrLen = 0;
00693 
00694             // Traversing the first record and process all fields which are editable:
00695             foreach($diff_1_record as $fN => $fV)   {
00696                 if ($TCA[$table]['columns'][$fN] && $TCA[$table]['columns'][$fN]['config']['type']!='passthrough' && !t3lib_div::inList('t3ver_label',$fN)) {
00697 
00698                     // Check if it is files:
00699                     $isFiles = FALSE;
00700                     if (strcmp(trim($diff_1_record[$fN]),trim($diff_2_record[$fN])) &&
00701                     $TCA[$table]['columns'][$fN]['config']['type']=='group' &&
00702                     $TCA[$table]['columns'][$fN]['config']['internal_type']=='file')    {
00703 
00704                         // Initialize:
00705                         $uploadFolder = $TCA[$table]['columns'][$fN]['config']['uploadfolder'];
00706                         $files1 = array_flip(t3lib_div::trimExplode(',', $diff_1_record[$fN],1));
00707                         $files2 = array_flip(t3lib_div::trimExplode(',', $diff_2_record[$fN],1));
00708 
00709                         // Traverse filenames and read their md5 sum:
00710                         foreach($files1 as $filename => $tmp)   {
00711                             $files1[$filename] = @is_file(PATH_site.$uploadFolder.'/'.$filename) ? md5(t3lib_div::getUrl(PATH_site.$uploadFolder.'/'.$filename)) : $filename;
00712                         }
00713                         foreach($files2 as $filename => $tmp)   {
00714                             $files2[$filename] = @is_file(PATH_site.$uploadFolder.'/'.$filename) ? md5(t3lib_div::getUrl(PATH_site.$uploadFolder.'/'.$filename)) : $filename;
00715                         }
00716 
00717                         // Implode MD5 sums and set flag:
00718                         $diff_1_record[$fN] = implode(' ',$files1);
00719                         $diff_2_record[$fN] = implode(' ',$files2);
00720                         $isFiles = TRUE;
00721                     }
00722 
00723                     // If there is a change of value:
00724                     if (strcmp(trim($diff_1_record[$fN]),trim($diff_2_record[$fN])))    {
00725 
00726 
00727                         // Get the best visual presentation of the value and present that:
00728                         $val1 = t3lib_BEfunc::getProcessedValue($table,$fN,$diff_2_record[$fN],0,1);
00729                         $val2 = t3lib_BEfunc::getProcessedValue($table,$fN,$diff_1_record[$fN],0,1);
00730 
00731                         // Make diff result and record string lenghts:
00732                         $diffres = $t3lib_diff_Obj->makeDiffDisplay($val1,$val2,$isFiles?'div':'span');
00733                         $diffStrLen+= $t3lib_diff_Obj->differenceLgd;
00734                         $allStrLen+= strlen($val1.$val2);
00735 
00736                         // If the compared values were files, substituted MD5 hashes:
00737                         if ($isFiles)   {
00738                             $allFiles = array_merge($files1,$files2);
00739                             foreach($allFiles as $filename => $token)   {
00740                                 if (strlen($token)==32 && strstr($diffres,$token))  {
00741                                     $filename =
00742                                     t3lib_BEfunc::thumbCode(array($fN=>$filename),$table,$fN,$this->doc->backPath).
00743                                     $filename;
00744                                     $diffres = str_replace($token,$filename,$diffres);
00745                                 }
00746                             }
00747                         }
00748 
00749                         // Add table row with result:
00750                         $tRows[] = '
00751                             <tr class="bgColor4">
00752                                 <td>'.htmlspecialchars($GLOBALS['LANG']->sL(t3lib_BEfunc::getItemLabel($table,$fN))).'</td>
00753                                 <td width="98%">'.$diffres.'</td>
00754                             </tr>
00755                         ';
00756                     } else {
00757                         // Add string lengths even if value matched - in this was the change percentage is not high if only a single field is changed:
00758                         $allStrLen+=strlen($diff_1_record[$fN].$diff_2_record[$fN]);
00759                     }
00760                 }
00761             }
00762 
00763             // Calculate final change percentage:
00764             $pctChange = $allStrLen ? ceil($diffStrLen*100/$allStrLen) : -1;
00765 
00766             // Create visual representation of result:
00767             if (count($tRows)>1)    {
00768                 $content.= '<table border="0" cellpadding="1" cellspacing="1" class="diffTable">'.implode('',$tRows).'</table>';
00769             } else {
00770                 $content.= '<span class="nobr">'.$this->doc->icons(1).$LANG->getLL('diffview_complete_match').'</span>';
00771             }
00772         } else $content.= $this->doc->icons(3).$LANG->getLL('diffview_cannot_find_records');
00773 
00774         // Return value:
00775         return array($content,$pctChange);
00776     }
00777 
00778     /**
00779      * Looking for versions of a record in other workspaces than the current
00780      *
00781      * @param   string      Table name
00782      * @param   integer     Record uid
00783      * @return  string      List of other workspace IDs
00784      */
00785     function versionsInOtherWS($table, $uid)    {
00786         // Check for duplicates:
00787         // Select all versions of record NOT in this workspace:
00788         $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
00789                 't3ver_wsid',
00790                 $table,
00791                 'pid=-1
00792                 AND t3ver_oid='.intval($uid).'
00793                 AND t3ver_wsid!='.intval($GLOBALS['BE_USER']->workspace).// TODO should be $this->workspaceId here???
00794                 ' AND (t3ver_wsid=-1 OR t3ver_wsid>0)'.
00795                 t3lib_BEfunc::deleteClause($table),
00796                 '',
00797                 't3ver_wsid',
00798                 '',
00799                 't3ver_wsid'
00800         );
00801         if (count($rows)) {
00802             return implode(',',array_keys($rows));
00803         }
00804     }
00805 
00806     /**
00807      * Looks up stage changes for version and displays a formatted view on mouseover.
00808      *
00809      * @param   string      Table name
00810      * @param   integer     Record ID
00811      * @param   string      HTML string to wrap the mouseover around (should be stage change links)
00812      * @return  string      HTML code.
00813      */
00814     function showStageChangeLog($table,$id,$stageCommands)  {
00815         global  $LANG;
00816 
00817         $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
00818                 'log_data,tstamp,userid',
00819                 'sys_log',
00820                 'action=6 and details_nr=30
00821                 AND tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table,'sys_log').'
00822                 AND recuid='.intval($id)
00823         );
00824 
00825         $entry = array();
00826         foreach($rows as $dat)  {
00827             $data = unserialize($dat['log_data']);
00828             $username = $this->be_user_Array[$dat['userid']] ? $this->be_user_Array[$dat['userid']]['username'] : '['.$dat['userid'].']';
00829 
00830             switch($data['stage'])  {
00831                 case 1:
00832                     $text = $LANG->getLL('stage_sent_to_review');
00833                     break;
00834                 case 10:
00835                     $text = $LANG->getLL('stage_approved_for_publish');
00836                     break;
00837                 case -1:
00838                     $text = $LANG->getLL('stage_rejected');
00839                     break;
00840                 case 0:
00841                     $text = $LANG->getLL('stage_reset_to_editing');
00842                     break;
00843                 default:
00844                     $text = $LANG->getLL('stage_undefined');
00845                     break;
00846             }
00847             $text = t3lib_BEfunc::datetime($dat['tstamp']).': ' . sprintf($text, htmlspecialchars($username));
00848             $text.= ($data['comment'] ? '<br />' . $LANG->getLL('stage_label_user_comment') . ' <em>' . htmlspecialchars($data['comment']) . '</em>' : '');
00849 
00850             $entry[] = $text;
00851         }
00852 
00853         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>' .
00854                 '<div class="t3-version-infolayer logLayer" id="log_' . $table . $id . '">' . implode('<hr/>', $entry) . '</div>' : $stageCommands;
00855     }
00856 
00857     /**
00858      * Links to publishing etc of a version
00859      *
00860      * @param   string      Table name
00861      * @param   array       Online record
00862      * @param   array       Offline record (version)
00863      * @param   string      Swap type, "branch", "page" or "element"
00864      * @return  string      HTML content, mainly link tags and images.
00865      */
00866     function displayWorkspaceOverview_commandLinks($table,&$rec_on,&$rec_off,$vType)    {
00867         global  $LANG;
00868 
00869         if ($this->publishAccess && (!($GLOBALS['BE_USER']->workspaceRec['publish_access']&1) || (int)$rec_off['t3ver_stage']===-10))   {
00870             $actionLinks =
00871                 '<a href="'.htmlspecialchars($this->doc->issueCommand(
00872                 '&cmd['.$table.']['.$rec_on['uid'].'][version][action]=swap'.
00873                 '&cmd['.$table.']['.$rec_on['uid'].'][version][swapWith]='.$rec_off['uid']
00874                 )).' " title="' . $LANG->getLL('img_title_publish') . '">'.
00875                   t3lib_iconWorks::getSpriteIcon('actions-version-workspace-sendtostage') .
00876                 '</a>';
00877             if ($GLOBALS['BE_USER']->workspaceSwapAccess()) {
00878                 $actionLinks.=
00879                     '<a href="'.htmlspecialchars($this->doc->issueCommand(
00880                     '&cmd['.$table.']['.$rec_on['uid'].'][version][action]=swap'.
00881                     '&cmd['.$table.']['.$rec_on['uid'].'][version][swapWith]='.$rec_off['uid'].
00882                     '&cmd['.$table.']['.$rec_on['uid'].'][version][swapIntoWS]=1'
00883                                 )).'" title="' . $LANG->getLL('img_title_swap') . '">'.
00884                       t3lib_iconWorks::getSpriteIcon('actions-version-swap-workspace') .
00885                     '</a>';
00886             }
00887         }
00888 
00889         if (!$GLOBALS['BE_USER']->workspaceCannotEditOfflineVersion($table,$rec_off)) {
00890             if ($GLOBALS['BE_USER']->workspace!==0) {
00891                 // Release
00892                 $confirm = $LANG->JScharCode($LANG->getLL('remove_from_ws_confirmation'));
00893                 $actionLinks.=
00894                 '<a href="'.htmlspecialchars($this->doc->issueCommand('&cmd['.$table.']['.$rec_off['uid'].'][version][action]=clearWSID')).'" onclick="return confirm(' . $confirm . ');" title="' . $LANG->getLL('img_title_remove_from_ws') . '">'.
00895                   t3lib_iconWorks::getSpriteIcon('actions-version-document-remove') .
00896                 '</a>';
00897             }
00898 
00899             // Edit
00900             if ($table==='pages' && $vType!=='element') {
00901                 $tempUid = ($vType==='branch' || $GLOBALS['BE_USER']->workspace===0 ? $rec_off['uid'] : $rec_on['uid']);
00902                 $actionLinks.=
00903                     '<a href="#" onclick="top.loadEditId('.$tempUid.');top.goToModule(\''.$this->pageModule.'\'); return false;" title="' . $LANG->getLL('img_title_edit_page') . '">'.
00904                       t3lib_iconWorks::getSpriteIcon('actions-page-open') .
00905                     '</a>';
00906             } else {
00907                 $params = '&edit['.$table.']['.$rec_off['uid'].']=edit';
00908                 $actionLinks.=
00909                     '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick($params,$this->doc->backPath)).'" title="' . $LANG->getLL('img_title_edit_element') . '">'.
00910                       t3lib_iconWorks::getSpriteIcon('actions-document-open') .
00911                     '</a>';
00912             }
00913         }
00914 
00915         // History/Log
00916         $actionLinks.=
00917             '<a href="'.htmlspecialchars($this->doc->backPath.'show_rechis.php?element='.rawurlencode($table.':'.$rec_off['uid']).'&returnUrl='.rawurlencode(t3lib_div::getIndpEnv('REQUEST_URI'))).'" title="' . $LANG->getLL('img_title_show_log') . '">' .
00918               t3lib_iconWorks::getSpriteIcon('actions-document-history-open') .
00919             '</a>';
00920 
00921         // View
00922         if ($table==='pages')   {
00923             $tempUid = ($vType==='branch' || $GLOBALS['BE_USER']->workspace===0 ? $rec_off['uid'] : $rec_on['uid']);
00924             $actionLinks.=
00925                 '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($tempUid,$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($tempUid))).'">'.
00926                   t3lib_iconWorks::getSpriteIcon('actions-document-view') .
00927                 '</a>';
00928         }
00929 
00930         return $actionLinks;
00931     }
00932 
00933     /**
00934      * Format publishing count for version (lifecycle state)
00935      *
00936      * @param   integer     t3ver_count value (number of times it has been online)
00937      * @return  string      String translation of count.
00938      */
00939     function formatCount($count)    {
00940         global  $LANG;
00941 
00942         // Render, if not cached:
00943         if (!isset($this->formatCount_cache[$count]))   {
00944             switch($count)  {
00945                 case 0:
00946                     $this->formatCount_cache[$count] = $LANG->getLL('workspace_list_publishing_count_draft');
00947                     break;
00948                 case 1:
00949                     $this->formatCount_cache[$count] = $LANG->getLL('workspace_list_publishing_count_archive');
00950                     break;
00951                 default:
00952                     $this->formatCount_cache[$count] = sprintf($LANG->getLL('workspace_list_publishing_count'), $count);
00953                     break;
00954             }
00955         }
00956 
00957         return $this->formatCount_cache[$count];
00958     }
00959 
00960 
00961     /**
00962      * Creates display of sub elements of a page when the swap mode is either "Page" or "Branch" (0 / ALL)
00963      *
00964      * @param   integer     Page uid (for either online or offline version, but it MUST have swapmode/treeLevel set to >0 (not -1 indicating element versioning)
00965      * @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!)
00966      * @param   integer     For offline versions; This is t3ver_oid, the original ID of the online page.
00967      * @return  string      HTML content.
00968      */
00969     function subElements($uid,$treeLevel,$origId=0) {
00970         global $TCA, $LANG;
00971 
00972         if ($GLOBALS['BE_USER']->workspace===0 || !$this->expandSubElements)    {   // In online workspace we have a reduced view because otherwise it will bloat the listing:
00973             return '<br />
00974                     <img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/ol/joinbottom.gif','width="18" height="16"').' align="top" alt="" title="" />'.
00975             ($origId ?
00976             '<a href="'.htmlspecialchars($this->doc->backPath.t3lib_extMgm::extRelPath('version').'cm1/index.php?id='.$uid.'&details='.rawurlencode('pages:'.$uid).'&returnUrl='.rawurlencode(t3lib_div::getIndpEnv('REQUEST_URI'))).'">'.
00977             '<span class="typo3-dimmed"><em>['.$LANG->getLL('label_subelementsdetails').']</em><span></a>' :
00978             '<span class="typo3-dimmed"><em>['.$LANG->getLL('label_subelements').']</em><span>');
00979         } else {    // For an offline workspace, show sub elements:
00980 
00981             $tCell = array();
00982 
00983             // Find records that follow pages when swapping versions:
00984             $recList = array();
00985             foreach($TCA as $tN => $tCfg)   {
00986                 if ($tN!='pages' && ($treeLevel>0 || $TCA[$tN]['ctrl']['versioning_followPages']))  {
00987                     $this->subElements_getNonPageRecords($tN, $uid, $recList);
00988                 }
00989             }
00990 
00991             // Render records collected above:
00992             $elCount = count($recList)-1;
00993             foreach($recList as $c => $comb)    {
00994                 list($tN,$rec) = $comb;
00995 
00996                 $this->subElements_renderItem(
00997                     $tCell,
00998                     $tN,
00999                     $uid,
01000                     $rec,
01001                     $origId,
01002                     $c==$elCount && $treeLevel==0 ? 1 : 0,      // If true, will show bottom-join icon.
01003                     ''
01004                 );
01005             }
01006 
01007             // For branch, dive into the subtree:
01008             if ($treeLevel>0) {
01009 
01010                 // Drawing tree:
01011                 $tree = t3lib_div::makeInstance('t3lib_pageTree');
01012                 $tree->init('AND '.$GLOBALS['BE_USER']->getPagePermsClause(1));
01013                 $tree->makeHTML = 2;        // 2=Also rendering depth-data into the result array
01014                 $tree->getTree($uid, 99, '');
01015 
01016                 // Traverse page tree:
01017                 foreach($tree->tree as $data)   {
01018 
01019                     // Render page in table cell:
01020                     $this->subElements_renderItem(
01021                         $tCell,
01022                         'pages',
01023                         $uid,
01024                         t3lib_BEfunc::getRecord('pages',$data['row']['uid']),   // Needs all fields, at least more than what is given in $data['row']...
01025                         $origId,
01026                         2,      // 2=the join icon and icon for the record is not rendered for pages (where all is in $data['HTML']
01027                         $data['HTML']
01028                     );
01029 
01030                     // Find all records from page and collect in $recList:
01031                     $recList = array();
01032                     foreach($TCA as $tN => $tCfg)   {
01033                         if ($tN!=='pages')  {
01034                             $this->subElements_getNonPageRecords($tN, $data['row']['uid'], $recList);
01035                         }
01036                     }
01037 
01038                     // Render records collected above:
01039                     $elCount = count($recList)-1;
01040                     foreach($recList as $c => $comb)    {
01041                         list($tN,$rec) = $comb;
01042 
01043                         $this->subElements_renderItem(
01044                             $tCell,
01045                             $tN,
01046                             $uid,
01047                             $rec,
01048                             $origId,
01049                             $c==$elCount?1:0,   // If true, will show bottom-join icon.
01050                             $data['HTML_depthData']
01051                         );
01052                     }
01053                 }
01054             }
01055 
01056             return '
01057                     <!-- Sub-element tree for versions -->
01058                     <table border="0" cellpadding="0" cellspacing="1" class="ver-subtree">
01059                         '.implode('',$tCell).'
01060                     </table>';
01061         }
01062     }
01063 
01064     /**
01065      * Select records from a table and add them to recList
01066      *
01067      * @param   string      Table name (from TCA)
01068      * @param   integer     PID to select records from
01069      * @param   array       Array where records are accumulated, passed by reference
01070      * @return  void
01071      */
01072     function subElements_getNonPageRecords($tN, $uid, &$recList)    {
01073         global $TCA;
01074 
01075         $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
01076             '*',
01077             $tN,
01078             'pid='.intval($uid).
01079             ($TCA[$tN]['ctrl']['versioningWS'] ? ' AND t3ver_state=0' : '').
01080             t3lib_BEfunc::deleteClause($tN),
01081             '',
01082             $TCA[$tN]['ctrl']['sortby'] ? $TCA[$tN]['ctrl']['sortby'] : $GLOBALS['TYPO3_DB']->stripOrderBy($TCA[$tN]['ctrl']['default_sortby'])
01083         );
01084 
01085         foreach($records as $rec)   {
01086             $recList[] = array($tN,$rec);
01087         }
01088     }
01089 
01090     /**
01091      * Render a single item in a subelement list into a table row:
01092      *
01093      * @param   array       Table rows, passed by reference
01094      * @param   string      Table name
01095      * @param   integer     Page uid for which the subelements are selected/shown
01096      * @param   array       Row of element in list
01097      * @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.
01098      * @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)
01099      * @param   string      Prefix HTML data (icons for tree rendering)
01100      * @return  void        (Content accumulated in $tCell!)
01101      */
01102     function subElements_renderItem(&$tCell,$tN,$uid,$rec,$origId,$iconMode,$HTMLdata)  {
01103         global $TCA;
01104 
01105         // Initialize:
01106         $origUidFields = $TCA[$tN]['ctrl']['origUid'];
01107         $diffCode = '';
01108 
01109         if ($origUidFields) {   // If there is a field for this table with original uids we will use that to connect records:
01110             if (!$origId)   {   // In case we are displaying the online originals:
01111                 $this->targets['orig_'.$uid.'_'.$tN.'_'.$rec['uid']] = $rec;    // Build up target array (important that
01112                 $tdParams =  ' id="orig_'.$uid.'_'.$tN.'_'.$rec['uid'].'" class="typo3-ver"';       // Setting ID of the table row
01113             } else {    // Version branch:
01114                 if ($this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]])   {   // If there IS a corresponding original record...:
01115 
01116                     // Prepare Table row parameters:
01117                     $this->addHlSubelementsScript = true;
01118                     $tdParams =  ' onmouseover="hlSubelements(\''.$origId.'_'.$tN.'_'.$rec[$origUidFields].'\', \''.$uid.'_'.$tN.'_'.$rec[$origUidFields].'\', 1, '.($this->diff==2?1:0).');"'.
01119                         ' onmouseout="hlSubelements(\''.$origId.'_'.$tN.'_'.$rec[$origUidFields].'\', \''.$uid.'_'.$tN.'_'.$rec[$origUidFields].'\', 0, '.($this->diff==2?1:0).');"'.
01120                         ' id="ver_'.$uid.'_'.$tN.'_'.$rec[$origUidFields].'" class="typo3-ver"';
01121 
01122                     // Create diff view:
01123                     if ($this->diff)    {
01124                         list($diffHTML,$diffPct) = $this->createDiffView($tN, $rec, $this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]]);
01125 
01126                         if ($this->diff==2) {
01127                             $diffCode =
01128                                 ($diffPct ? '<span class="nobr">'.$diffPct.'% change</span>' : '-').
01129                                 '<div style="visibility: hidden; position: absolute;" id="diff_'.$uid.'_'.$tN.'_'.$rec[$origUidFields].'" class="diffLayer">'.
01130                                 $diffHTML.
01131                                 '</div>';
01132                         } else {
01133                             $diffCode =
01134                                 ($diffPct<0 ? 'N/A' : ($diffPct ? $diffPct.'% change:' : '')).
01135                                 $diffHTML;
01136                         }
01137                     }
01138 
01139                     // Unsetting the target fields allows us to mark all originals without a version in the subtree (see ->markupNewOriginals())
01140                     unset($this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]]);
01141                 } else {    // No original record, so must be new:
01142                     $tdParams =  ' class="typo3-ver-new"';
01143                 }
01144             }
01145         } else {    // If no original uid column is supported for this table we are forced NOT to display any diff or highlighting.
01146             $tdParams = ' class="typo3-ver-noComp"';
01147         }
01148 
01149         // Compile the cell:
01150         $tCell[] = '
01151                         <tr'.$tdParams.'>
01152                             <td class="iconTitle">'.
01153                             $HTMLdata.
01154                             ($iconMode < 2 ?
01155                             '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/ol/join'.($iconMode ? 'bottom' : '').'.gif','width="18" height="16"').' alt="" />'.
01156                             t3lib_iconWorks::getIconImage($tN, $rec, $this->doc->backPath,'') : '').
01157                             t3lib_BEfunc::getRecordTitle($tN, $rec, TRUE).
01158                             '</td>
01159                             <td class="cmdCell">'.
01160                             $this->displayWorkspaceOverview_commandLinksSub($tN,$rec,$origId).
01161                             '</td>'.($origId ? '<td class="diffCell">'.
01162                             $diffCode.
01163                             '</td>':'').'
01164                         </tr>';
01165     }
01166 
01167     /**
01168      * Links to publishing etc of a version
01169      *
01170      * @param   string      Table name
01171      * @param   array       Record array
01172      * @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.
01173      * @return  string      HTML content, mainly link tags and images.
01174      */
01175     function displayWorkspaceOverview_commandLinksSub($table,$rec,$origId)  {
01176         global $LANG;
01177 
01178         $uid = $rec['uid'];
01179         if ($origId || $GLOBALS['BE_USER']->workspace===0)  {
01180             if (!$GLOBALS['BE_USER']->workspaceCannotEditRecord($table,$rec))   {
01181                 // Edit
01182                 if ($table==='pages')   {
01183                     $actionLinks.=
01184                         '<a href="#" onclick="top.loadEditId('.$uid.');top.goToModule(\''.$this->pageModule.'\'); return false;" title="' . $LANG->getLL('img_title_edit_page') . '">'.
01185                           t3lib_iconWorks::getSpriteIcon('actions-page-open') .
01186                         '</a>';
01187                 } else {
01188                     $params = '&edit['.$table.']['.$uid.']=edit';
01189                     $actionLinks.=
01190                         '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick($params,$this->doc->backPath)).'" title="' . $LANG->getLL('img_title_edit_element') . '">'.
01191                           t3lib_iconWorks::getSpriteIcon('actions-document-open') .
01192                         '</a>';
01193                 }
01194             }
01195 
01196             // History/Log
01197             $actionLinks.=
01198                 '<a href="'.htmlspecialchars($this->doc->backPath.'show_rechis.php?element='.rawurlencode($table.':'.$uid).'&returnUrl='.rawurlencode(t3lib_div::getIndpEnv('REQUEST_URI'))).'" title="' . $LANG->getLL('img_title_show_log') . '">'.
01199                   t3lib_iconWorks::getSpriteIcon('actions-document-history-open') .
01200                 '</a>';
01201         }
01202 
01203         // View
01204         if ($table==='pages')   {
01205             $actionLinks.=
01206                 '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($uid,$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($uid))).'">'.
01207                   t3lib_iconWorks::getSpriteIcon('actions-document-view') .
01208                 '</a>';
01209         }
01210 
01211         return $actionLinks;
01212     }
01213 
01214 
01215     /**
01216      * Links to stage change of a version
01217      *
01218      * @param   string      Table name
01219      * @param   array       Offline record (version)
01220      * @return  string      HTML content, mainly link tags and images.
01221      */
01222     function displayWorkspaceOverview_stageCmd($table,&$rec_off)    {
01223         global $LANG;
01224 
01225         switch((int)$rec_off['t3ver_stage'])    {
01226             case 0:
01227                 $sId = 1;
01228                 $sLabel = $LANG->getLL('stage_editing');
01229                 $color = '#666666'; // TODO Use CSS?
01230                 $label = $LANG->getLL('label_commentforreviewer');
01231                 $titleAttrib = $LANG->getLL('label_sendtoreview');
01232                 break;
01233             case 1:
01234                 $sId = 10;
01235                 $sLabel = $LANG->getLL('label_review');
01236                 $color = '#6666cc'; // TODO Use CSS?
01237                 $label = $LANG->getLL('label_commentforpublisher');
01238                 $titleAttrib = $LANG->getLL('label_approveforpublishing');
01239                 break;
01240             case 10:
01241                 $sLabel = $LANG->getLL('label_publish');
01242                 $color = '#66cc66'; // TODO Use CSS?
01243                 break;
01244             case -1:
01245                 $sLabel = $this->doc->icons(2).$LANG->getLL('label_rejected');
01246                 $sId = 0;
01247                 $color = '#ff0000'; // TODO Use CSS?
01248                 $label = $LANG->getLL('stage_label_user_comment');
01249                 $titleAttrib = $LANG->getLL('label_resetstage');
01250                 break;
01251             default:
01252                 $sLabel = $LANG->getLL('label_undefined');
01253                 $sId = 0;
01254                 $color = '';
01255                 break;
01256         }
01257         #debug($sId);
01258 
01259         $raiseOk = !$GLOBALS['BE_USER']->workspaceCannotEditOfflineVersion($table,$rec_off);
01260 
01261         if ($raiseOk && $rec_off['t3ver_stage'] != -1 && $GLOBALS['BE_USER']->workspaceCheckStageForCurrent($sId))  {
01262             $onClick = 'var commentTxt=window.prompt("'.$LANG->getLL('explain_reject').'","");
01263                             if (commentTxt!=null) {window.location.href="'.$this->doc->issueCommand(
01264             '&cmd['.$table.']['.$rec_off['uid'].'][version][action]=setStage'.
01265             '&cmd['.$table.']['.$rec_off['uid'].'][version][stageId]=-1'
01266                             ).'&cmd['.$table.']['.$rec_off['uid'].'][version][comment]="+escape(commentTxt);}'.
01267             ' return false;';
01268             // Reject:
01269             $actionLinks.=
01270             '<a href="#" onclick="'.htmlspecialchars($onClick).'"title="'.$LANG->getLL('label_reject').'"> '.
01271               t3lib_iconWorks::getSpriteIcon('actions-move-down') .
01272             '</a>';
01273         } else {
01274             // Reject:
01275             $actionLinks.=
01276             '<img src="'.$this->doc->backPath.'gfx/clear.gif" width="14" height="14" alt="" align="top" title="" />';
01277         }
01278 
01279         // TODO Use CSS?
01280         $actionLinks.= '<span style="background-color: '.$color.'; color: white;">'.$sLabel.'</span>';
01281 
01282         // Raise
01283         if ($raiseOk && $GLOBALS['BE_USER']->workspaceCheckStageForCurrent($sId))   {
01284             $onClick = 'var commentTxt=window.prompt("'.$label.'","");
01285                             if (commentTxt!=null) {window.location.href="'.$this->doc->issueCommand(
01286             '&cmd['.$table.']['.$rec_off['uid'].'][version][action]=setStage'.
01287             '&cmd['.$table.']['.$rec_off['uid'].'][version][stageId]='.$sId
01288             ).'&cmd['.$table.']['.$rec_off['uid'].'][version][comment]="+escape(commentTxt);}'.
01289             ' return false;';
01290             if ($rec_off['t3ver_stage']!=10)    {
01291                 $actionLinks.=
01292                 '<a href="#" onclick="'.htmlspecialchars($onClick).'" title="'.htmlspecialchars($titleAttrib).'">'.
01293                   t3lib_iconWorks::getSpriteIcon('actions-move-up') .
01294                 '</a>';
01295 
01296                 $this->stageIndex[$sId][$table][] = $rec_off['uid'];
01297             }
01298         }
01299 
01300         return $actionLinks;
01301     }
01302 }
01303 
01304 
01305 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3/mod/user/ws/class.wslib_gui.php'])) {
01306     include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3/mod/user/ws/class.wslib_gui.php']);
01307 }
01308 
01309 ?>