|
TYPO3 API
SVNRelease
|
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.' </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 ' '; 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 ?>
1.8.0