"TYPO3 4.0.1: typo3_src-4.0.1/typo3/mod/user/ws/index.php Source File", "datetime" => "Sat Dec 2 19:22:16 2006", "date" => "2 Dec 2006", "doxygenversion" => "1.4.6", "projectname" => "TYPO3 4.0.1", "projectnumber" => "4.0.1" ); get_header($doxygen_vars); ?>
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 1999-2005 Kasper Skaarhoj (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 ***************************************************************/ 00095 // Initialize module: 00096 unset($MCONF); 00097 require ('conf.php'); 00098 require ($BACK_PATH.'init.php'); 00099 require ($BACK_PATH.'template.php'); 00100 $BE_USER->modAccess($MCONF,1); 00101 00102 // Include libraries of various kinds used inside: 00103 $LANG->includeLLFile('EXT:lang/locallang_mod_user_ws.xml'); 00104 require_once(PATH_t3lib.'class.t3lib_scbase.php'); 00105 require_once(PATH_typo3.'mod/user/ws/class.wslib.php'); 00106 require_once(PATH_t3lib.'class.t3lib_diff.php'); 00107 require_once(PATH_t3lib.'class.t3lib_pagetree.php'); 00108 require_once(PATH_t3lib.'class.t3lib_tcemain.php'); 00109 00110 00111 00112 00120 class SC_mod_user_ws_index extends t3lib_SCbase { 00121 00122 // Static: 00123 var $pageTreeIndent = 8; 00124 var $pageTreeIndent_titleLgd = 30; 00125 00126 // Default variables for backend modules 00127 var $MCONF = array(); // Module configuration 00128 var $MOD_MENU = array(); // Module menu items 00129 var $MOD_SETTINGS = array(); // Module session settings 00130 var $doc; // Document Template Object 00131 var $content; // Accumulated content 00132 00133 00134 // Internal: 00135 var $showWorkspaceCol = 0; 00136 var $formatWorkspace_cache = array(); 00137 var $formatCount_cache = array(); 00138 var $targets = array(); // Accumulation of online targets. 00139 var $pageModule = ''; 00140 var $publishAccess = FALSE; 00141 var $be_user_Array = array(); 00142 var $be_user_Array_full = array(); // not blinded, used by workspace listing 00143 var $stageIndex = array(); 00144 00145 00146 /********************************* 00147 * 00148 * Standard module initialization 00149 * 00150 *********************************/ 00151 00157 function menuConfig() { 00158 global $LANG; 00159 00160 // Menu items: 00161 $this->MOD_MENU = array( 00162 'function' => array( 00163 'publish' => $LANG->getLL('menuitem_review'), 00164 'workspaces' => $LANG->getLL('menuitem_workspaces'), 00165 ), 00166 'filter' => array( 00167 1 => $LANG->getLL('filter_drafts'), 00168 2 => $LANG->getLL('filter_archive'), 00169 0 => $LANG->getLL('filter_all'), 00170 ), 00171 'display' => array( 00172 0 => '[Live workspace]', 00173 -98 => 'Draft Workspaces', 00174 -99 => 'All', 00175 -1 => '[Default Draft]' 00176 ), 00177 'diff' => array( 00178 0 => $LANG->getLL('diff_no_diff'), 00179 1 => $LANG->getLL('diff_show_inline'), 00180 2 => $LANG->getLL('diff_show_popup'), 00181 ), 00182 'expandSubElements' => '', 00183 ); 00184 00185 // Add workspaces: 00186 if ($GLOBALS['BE_USER']->workspace===0) { // Spend time on this only in online workspace because it might take time: 00187 $workspaces = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,title,adminusers,members,reviewers','sys_workspace','pid=0'.t3lib_BEfunc::deleteClause('sys_workspace'),'','title'); 00188 foreach($workspaces as $rec) { 00189 if ($GLOBALS['BE_USER']->checkWorkspace($rec)) { 00190 $this->MOD_MENU['display'][$rec['uid']] = '['.$rec['uid'].'] '.$rec['title']; 00191 } 00192 } 00193 } 00194 00195 // CLEANSE SETTINGS 00196 $this->MOD_SETTINGS = t3lib_BEfunc::getModuleData($this->MOD_MENU, t3lib_div::_GP('SET'), $this->MCONF['name'], 'ses'); 00197 } 00198 00204 function init() { 00205 global $BACK_PATH, $BE_USER; 00206 00207 // Setting module configuration: 00208 $this->MCONF = $GLOBALS['MCONF']; 00209 00210 // Initialize Document Template object: 00211 $this->doc = t3lib_div::makeInstance('noDoc'); 00212 $this->doc->backPath = $BACK_PATH; 00213 $this->doc->docType = 'xhtml_trans'; 00214 00215 // JavaScript 00216 $plusIcon = t3lib_iconWorks::skinImg($BACK_PATH, 'gfx/ol/plusbullet.gif', 'width="18" height="16"', 1); 00217 $minusIcon = t3lib_iconWorks::skinImg($BACK_PATH, 'gfx/ol/minusbullet.gif', 'width="18" height="16"', 1); 00218 $this->doc->JScode = $this->doc->wrapScriptTags(' 00219 script_ended = 0; 00220 function jumpToUrl(URL) { // 00221 window.location.href = URL; 00222 } 00223 00224 function hlSubelements(origId, verId, over, diffLayer) { // 00225 if (over) { 00226 document.getElementById(\'orig_\'+origId).attributes.getNamedItem("class").nodeValue = \'typo3-ver-hl\'; 00227 document.getElementById(\'ver_\'+verId).attributes.getNamedItem("class").nodeValue = \'typo3-ver-hl\'; 00228 if (diffLayer) { 00229 document.getElementById(\'diff_\'+verId).style.visibility = \'visible\'; 00230 } 00231 } else { 00232 document.getElementById(\'orig_\'+origId).attributes.getNamedItem("class").nodeValue = \'typo3-ver\'; 00233 document.getElementById(\'ver_\'+verId).attributes.getNamedItem("class").nodeValue = \'typo3-ver\'; 00234 if (diffLayer) { 00235 document.getElementById(\'diff_\'+verId).style.visibility = \'hidden\'; 00236 } 00237 } 00238 } 00239 00240 function expandCollapse(rowNumber) { // 00241 elementId = \'wl_\' + rowNumber; 00242 element = document.getElementById(elementId); 00243 image = document.getElementById(elementId + \'i\'); 00244 if (element.style) { 00245 if (element.style.display == \'none\') { 00246 element.style.display = \'\'; 00247 image.src = \'' . $minusIcon . '\'; 00248 } else { 00249 element.style.display = \'none\'; 00250 image.src = \'' . $plusIcon . '\'; 00251 } 00252 } 00253 } 00254 '); 00255 $this->doc->form = '<form action="index.php" method="post" name="pageform">'; 00256 00257 // Setting up the context sensitive menu: 00258 $CMparts = $this->doc->getContextMenuCode(); 00259 $this->doc->JScode.= $CMparts[0]; 00260 $this->doc->bodyTagAdditions = $CMparts[1]; 00261 $this->doc->postCode.= $CMparts[2]; 00262 00263 // Add JS for dynamic tabs: 00264 $this->doc->JScode.= $this->doc->getDynTabMenuJScode(); 00265 00266 // If another page module was specified, replace the default Page module with the new one 00267 $newPageModule = trim($BE_USER->getTSConfigVal('options.overridePageModule')); 00268 $this->pageModule = t3lib_BEfunc::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout'; 00269 00270 // Setting publish access permission for workspace: 00271 $this->publishAccess = $BE_USER->workspacePublishAccess($BE_USER->workspace); 00272 00273 // Parent initialization: 00274 parent::init(); 00275 } 00276 00282 function main() { 00283 global $LANG, $BE_USER, $BACK_PATH; 00284 00285 // See if we need to switch workspace 00286 $changeWorkspace = t3lib_div::_GET('changeWorkspace'); 00287 if ($changeWorkspace != '') { 00288 $BE_USER->setWorkspace($changeWorkspace); 00289 $this->content = $this->doc->startPage($LANG->getLL('title')); 00290 $this->content .= $this->doc->wrapScriptTags('top.location.href="' . $BACK_PATH . 'alt_main.php";'); 00291 } 00292 else { 00293 // Perform workspace publishing action if buttons are pressed: 00294 $errors = $this->publishAction(); 00295 00296 // Starting page: 00297 $this->content.=$this->doc->startPage($LANG->getLL('title')); 00298 $this->content.=$this->doc->header($LANG->getLL('title')); 00299 $this->content.=$this->doc->spacer(5); 00300 00301 // Build top menu: 00302 $menuItems = array(); 00303 $menuItems[] = array( 00304 'label' => $LANG->getLL('menuitem_review'), 00305 'content' => (count($errors) ? '<h3>' . $LANG->getLL('label_errors') . '</h3><br/>'.implode('<br/>',$errors).'<hr/>' : '').$this->moduleContent_publish() 00306 ); 00307 $menuItems[] = array( 00308 'label' => $LANG->getLL('menuitem_workspaces'), 00309 'content' => $this->moduleContent_workspaceList() 00310 ); 00311 00312 // Add hidden fields and create tabs: 00313 $content = $this->doc->getDynTabMenu($menuItems,'user_ws'); 00314 $this->content.=$this->doc->section('',$content,0,1); 00315 } 00316 } 00317 00323 function printContent() { 00324 global $SOBE; 00325 00326 $this->content.= $this->doc->endPage(); 00327 echo $this->content; 00328 } 00329 00330 00331 00332 00333 00334 00335 00336 00337 00338 00339 00340 00341 00342 /********************************* 00343 * 00344 * Module content: Publish 00345 * 00346 *********************************/ 00347 00353 function moduleContent_publish() { 00354 global $LANG; 00355 00356 // Initialize: 00357 $content = ''; 00358 $details = t3lib_div::_GP('details'); 00359 00360 // Create additional menus: 00361 $menu = ''; 00362 if ($GLOBALS['BE_USER']->workspace===0) { 00363 $menu.= t3lib_BEfunc::getFuncMenu(0,'SET[filter]',$this->MOD_SETTINGS['filter'],$this->MOD_MENU['filter']); 00364 $menu.= t3lib_BEfunc::getFuncMenu(0,'SET[display]',$this->MOD_SETTINGS['display'],$this->MOD_MENU['display']); 00365 } 00366 $menu.= t3lib_BEfunc::getFuncMenu(0,'SET[diff]',$this->MOD_SETTINGS['diff'],$this->MOD_MENU['diff']); 00367 if ($GLOBALS['BE_USER']->workspace!==0) { 00368 $menu.= t3lib_BEfunc::getFuncCheck(0,'SET[expandSubElements]',$this->MOD_SETTINGS['expandSubElements']).' Show sub-elements - '; 00369 } 00370 00371 // Create header: 00372 $title = ''; 00373 $description = ''; 00374 switch($GLOBALS['BE_USER']->workspace) { 00375 case 0: 00376 $title = t3lib_iconWorks::getIconImage('sys_workspace', array(), $this->doc->backPath, ' align="top"').'[LIVE workspace]'; 00377 $description = $LANG->getLL('workspace_description_live'); 00378 break; 00379 case -1: 00380 $title = t3lib_iconWorks::getIconImage('sys_workspace', array(), $this->doc->backPath, ' align="top"').'[Draft workspace]'; 00381 $description = $LANG->getLL('workspace_description_draft'); 00382 break; 00383 case -99: 00384 $title = $this->doc->icons(3).'[NONE]'; 00385 $description = $LANG->getLL('workspace_description_no_access'); 00386 break; 00387 default: 00388 $title = t3lib_iconWorks::getIconImage('sys_workspace', $GLOBALS['BE_USER']->workspaceRec, $this->doc->backPath, ' align="top"'). 00389 '['.$GLOBALS['BE_USER']->workspace.'] '.t3lib_BEfunc::getRecordTitle('sys_workspace',$GLOBALS['BE_USER']->workspaceRec,TRUE); 00390 $description = ($GLOBALS['BE_USER']->workspaceRec['description'] ? htmlspecialchars($GLOBALS['BE_USER']->workspaceRec['description']) : '<em>[None]</em>'); 00391 break; 00392 } 00393 00394 // Buttons for publish / swap: 00395 $actionLinks = ''; 00396 if ($GLOBALS['BE_USER']->workspace!==0) { 00397 if ($this->publishAccess) { 00398 $confirmation = $LANG->JScharCode($LANG->getLL(($GLOBALS['BE_USER']->workspaceRec['publish_access'] & 1) ? 'submit_publish_workspace_confirmation_1' : 'submit_publish_workspace_confirmation_2')); 00399 $actionLinks.= '<input type="submit" name="_publish" value="' . $LANG->getLL('submit_publish_workspace') . '" onclick="return confirm(' . $confirmation . ');"/>'; 00400 if ($GLOBALS['BE_USER']->workspaceSwapAccess()) { 00401 $confirmation = $LANG->JScharCode($LANG->getLL(($GLOBALS['BE_USER']->workspaceRec['publish_access'] & 1) ? 'submit_swap_workspace_confirmation_1' : 'submit_swap_workspace_confirmation_2')); 00402 $actionLinks.= '<input type="submit" name="_swap" value="' . $LANG->getLL('submit_swap_workspace') . '" onclick="return confirm(' . $confirmation . ');" />'; 00403 } 00404 } else { 00405 $actionLinks.= $this->doc->icons(1) . $LANG->getLL('no_publish_permission'); 00406 } 00407 } 00408 00409 $wsAccess = $GLOBALS['BE_USER']->checkWorkspace($GLOBALS['BE_USER']->workspaceRec); 00410 00411 // Add header to content variable: 00412 $content = ' 00413 <table border="0" cellpadding="1" cellspacing="1" class="lrPadding" style="border: 1px solid black;"> 00414 <tr> 00415 <td class="bgColor2" nowrap="nowrap"><b>' . $LANG->getLL('label_workspace') . '</b> </td> 00416 <td class="bgColor4" nowrap="nowrap">'.$title.'</td> 00417 </tr> 00418 <tr> 00419 <td class="bgColor2" nowrap="nowrap"><b>' . $LANG->getLL('label_description') . '</b> </td> 00420 <td class="bgColor4">'.$description.'</td> 00421 </tr>'.($GLOBALS['BE_USER']->workspace!=-99 && !$details ? ' 00422 <tr> 00423 <td class="bgColor2" nowrap="nowrap"><b>' . $LANG->getLL('label_options') . '</b> </td> 00424 <td class="bgColor4">'.$menu.$actionLinks.'</td> 00425 </tr> 00426 <tr> 00427 <td class="bgColor2" nowrap="nowrap"><b>' . $LANG->getLL('label_status') . '</b> </td> 00428 <td class="bgColor4">Access level: ' . $GLOBALS['LANG']->getLL('workspace_list_access_' . $wsAccess['_ACCESS']) . '</td> 00429 </tr>' : '').' 00430 </table> 00431 <br/> 00432 '; 00433 00434 // Add publishing and review overview: 00435 if ($GLOBALS['BE_USER']->workspace!=-99) { 00436 if ($details) { 00437 $content.= $this->displayVersionDetails($details); 00438 } else { 00439 $content.= $this->displayWorkspaceOverview(); 00440 } 00441 $content.='<br/>'; 00442 } 00443 00444 // Return content: 00445 return $content; 00446 } 00447 00454 function displayVersionDetails($details) { 00455 return 'TODO: Show details for version "'.$details.'"<hr/><a href="index.php">BACK</a>'; 00456 } 00457 00463 function displayWorkspaceOverview() { 00464 global $LANG; 00465 00466 // Initialize variables: 00467 $this->showWorkspaceCol = $GLOBALS['BE_USER']->workspace===0 && $this->MOD_SETTINGS['display']<=-98; 00468 00469 // Get usernames and groupnames 00470 $be_group_Array = t3lib_BEfunc::getListGroupNames('title,uid'); 00471 $groupArray = array_keys($be_group_Array); 00472 // Need 'admin' field for t3lib_iconWorks::getIconImage() 00473 $this->be_user_Array_full = $this->be_user_Array = t3lib_BEfunc::getUserNames('username,usergroup,usergroup_cached_list,uid,admin,workspace_perms'); 00474 if (!$GLOBALS['BE_USER']->isAdmin()) $this->be_user_Array = t3lib_BEfunc::blindUserNames($this->be_user_Array,$groupArray,1); 00475 00476 // Initialize Workspace ID and filter-value: 00477 if ($GLOBALS['BE_USER']->workspace===0) { 00478 $wsid = $this->MOD_SETTINGS['display']; // Set wsid to the value from the menu (displaying content of other workspaces) 00479 $filter = $this->MOD_SETTINGS['filter']; 00480 } else { 00481 $wsid = $GLOBALS['BE_USER']->workspace; 00482 $filter = 0; 00483 } 00484 00485 // Initialize workspace object and request all pending versions: 00486 $wslibObj = t3lib_div::makeInstance('wslib'); 00487 00488 // Selecting ALL versions belonging to the workspace: 00489 $versions = $wslibObj->selectVersionsInWorkspace($wsid, $filter); 00490 00491 // Traverse versions and build page-display array: 00492 $pArray = array(); 00493 foreach($versions as $table => $records) { 00494 if (is_array($records)) { 00495 foreach($records as $rec) { 00496 $pageIdField = $table==='pages' ? 't3ver_oid' : 'realpid'; 00497 $this->displayWorkspaceOverview_setInPageArray( 00498 $pArray, 00499 t3lib_BEfunc::BEgetRootLine($rec[$pageIdField], 'AND 1=1'), 00500 $table, 00501 $rec 00502 ); 00503 } 00504 } 00505 } 00506 00507 // Make header of overview: 00508 $tableRows = array(); 00509 $tableRows[] = ' 00510 <tr class="bgColor5 tableheader"> 00511 <td nowrap="nowrap" width="100">' . $LANG->getLL('label_pagetree') . '</td> 00512 <td nowrap="nowrap" colspan="2">' . $LANG->getLL('label_live_version') . '</td> 00513 <td nowrap="nowrap" colspan="2">' . $LANG->getLL('label_draft_versions') . '</td> 00514 <td nowrap="nowrap">' . $LANG->getLL('label_stage') . '</td> 00515 <td nowrap="nowrap">' . $LANG->getLL('label_publish') . '</td> 00516 <td>' . $LANG->getLL('label_lifecycle') . '</td> 00517 '.($this->showWorkspaceCol ? '<td>' . $LANG->getLL('label_workspace') . '</td>' : '').' 00518 </tr>'; 00519 00520 // Add lines from overview: 00521 $tableRows = array_merge($tableRows, $this->displayWorkspaceOverview_list($pArray)); 00522 00523 $table = '<table border="0" cellpadding="0" cellspacing="1" class="lrPadding workspace-overview">'.implode('',$tableRows).'</table>'; 00524 00525 return $table.$this->markupNewOriginals(); 00526 } 00527 00538 function displayWorkspaceOverview_list($pArray, $tableRows=array(), $c=0, $warnAboutVersions=FALSE) { 00539 global $TCA; 00540 00541 // Initialize: 00542 $fullColSpan = ($this->showWorkspaceCol?9:8); 00543 00544 // Traverse $pArray 00545 if (is_array($pArray)) { 00546 foreach($pArray as $k => $v) { 00547 if (t3lib_div::testInt($k)) { 00548 00549 // If there are elements on this level, output a divider row which just creates a little visual space. 00550 if (is_array($pArray[$k.'_'])) { 00551 $tableRows[] = ' 00552 <tr> 00553 <td colspan="'.$fullColSpan.'"><img src="clear.gif" width="1" height="3" alt="" /></td> 00554 </tr>'; 00555 } 00556 00557 // Printing a level from the page tree with no additional content: 00558 // 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) 00559 if (!is_array($pArray[$k.'_']) || !is_array($pArray[$k.'_']['pages'])) { 00560 $tableRows[] = ' 00561 <tr class="bgColor4-20"> 00562 <td nowrap="nowrap" colspan="'.$fullColSpan.'">'. 00563 $this->displayWorkspaceOverview_pageTreeIconTitle($k,$pArray[$k],$c). 00564 '</td> 00565 </tr>'; 00566 } 00567 00568 // If there ARE elements on this level, print them: 00569 $warnAboutVersions_next = $warnAboutVersions; 00570 $warnAboutVersions_nonPages = FALSE; 00571 $warnAboutVersions_page = FALSE; 00572 if (is_array($pArray[$k.'_'])) { 00573 foreach($pArray[$k.'_'] as $table => $oidArray) { 00574 foreach($oidArray as $oid => $recs) { 00575 00576 // Get CURRENT online record and icon based on "t3ver_oid": 00577 $rec_on = t3lib_BEfunc::getRecord($table,$oid); 00578 $icon = t3lib_iconWorks::getIconImage($table, $rec_on, $this->doc->backPath,' align="top" title="'.t3lib_BEfunc::getRecordIconAltText($rec_on,$table).'"'); 00579 if ($GLOBALS['BE_USER']->workspace===0) { // Only edit online records if in ONLINE workspace: 00580 $icon = $this->doc->wrapClickMenuOnIcon($icon, $table, $rec_on['uid'], 2, '', '+edit,view,info,delete'); 00581 } 00582 00583 // MAIN CELL / Online version display: 00584 // 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) 00585 $verLinkUrl = t3lib_extMgm::isLoaded('version') && $TCA[$table]['ctrl']['versioningWS']; 00586 $origElement = $icon. 00587 ($verLinkUrl ? '<a href="'.htmlspecialchars($this->doc->backPath.t3lib_extMgm::extRelPath('version').'cm1/index.php?table='.$table.'&uid='.$rec_on['uid']).'">' : ''). 00588 t3lib_BEfunc::getRecordTitle($table,$rec_on,TRUE). 00589 ($verLinkUrl ? '</a>' : ''); 00590 $mainCell_rowSpan = count($recs)>1 ? ' rowspan="'.count($recs).'"' : ''; 00591 $mainCell = $table==='pages' ? ' 00592 <td class="bgColor4-20" nowrap="nowrap"'.$mainCell_rowSpan.'>'. 00593 $this->displayWorkspaceOverview_pageTreeIconTitle($k,$pArray[$k],$c). 00594 '</td>' : ' 00595 <td class="bgColor"'.$mainCell_rowSpan.'></td>'; 00596 $mainCell.= ' 00597 <td align="center"'.$mainCell_rowSpan.'>'.$this->formatVerId($rec_on['t3ver_id']).'</td> 00598 <td nowrap="nowrap"'.$mainCell_rowSpan.'>'. 00599 $origElement. 00600 '###SUB_ELEMENTS###'. // For substitution with sub-elements, if any. 00601 '</td>'; 00602 00603 // Offline versions display: 00604 // Traverse the versions of the element 00605 foreach($recs as $rec) { 00606 00607 // Get the offline version record and icon: 00608 $rec_off = t3lib_BEfunc::getRecord($table,$rec['uid']); 00609 $icon = t3lib_iconWorks::getIconImage($table, $rec_off, $this->doc->backPath, ' align="top" title="'.t3lib_BEfunc::getRecordIconAltText($rec_off,$table).'"'); 00610 $icon = $this->doc->wrapClickMenuOnIcon($icon, $table, $rec_off['uid'], 2, '', '+edit,view,info,delete'); 00611 00612 // Prepare diff-code: 00613 if ($this->MOD_SETTINGS['diff']) { 00614 $diffCode = ''; 00615 list($diffHTML,$diffPct) = $this->createDiffView($table, $rec_off, $rec_on); 00616 if ($rec_on['t3ver_state']==1) { // New record: 00617 $diffCode.= $this->doc->icons(1).'New element<br/>'; // TODO Localize? 00618 $diffCode.= $diffHTML; 00619 } elseif ($rec_off['t3ver_state']==2) { 00620 $diffCode.= $this->doc->icons(2).'Deleted element<br/>'; 00621 } else { 00622 $diffCode.= ($diffPct<0 ? 'N/A' : ($diffPct ? $diffPct.'% change:' : '')); 00623 $diffCode.= $diffHTML; 00624 } 00625 00626 } else $diffCode = ''; 00627 00628 // Prepare swap-mode values: 00629 if ($table==='pages' && $rec_off['t3ver_swapmode']!=-1) { 00630 if ($rec_off['t3ver_swapmode']>0) { 00631 $vType = 'branch'; // Do not translate! 00632 } else { 00633 $vType = 'page'; // Do not translate! 00634 } 00635 } else { 00636 $vType = 'element'; // Do not translate! 00637 } 00638 00639 switch($vType) { 00640 case 'element': 00641 $swapLabel = ' [Element]'; // TODO Localize? 00642 $swapClass = 'ver-element'; // Do not translate! 00643 $warnAboutVersions_nonPages = $warnAboutVersions_page; // Setting this if sub elements are found with a page+content (must be rendered prior to this of course!) 00644 break; 00645 case 'page': 00646 $swapLabel = ' [Page]'; // TODO Localize? 00647 $swapClass = 'ver-page'; // Do not translate! 00648 $warnAboutVersions_page = !$this->showWorkspaceCol; // This value is true only if multiple workspaces are shown and we need the opposite here. 00649 break; 00650 case 'branch': 00651 $swapLabel = ' [Branch]'; // TODO Localize? 00652 $swapClass = 'ver-branch'; // Do not translate! 00653 $warnAboutVersions_next = !$this->showWorkspaceCol; // This value is true only if multiple workspaces are shown and we need the opposite here. 00654 break; 00655 } 00656 00657 // Modify main cell based on first version shown: 00658 $subElements = array(); 00659 if ($table==='pages' && $rec_off['t3ver_swapmode']!=-1 && $mainCell) { // For "Page" and "Branch" swap modes where $mainCell is still carrying content (only first version) 00660 $subElements['on'] = $this->subElements($rec_on['uid'], $rec_off['t3ver_swapmode']); 00661 $subElements['off'] = $this->subElements($rec_off['uid'],$rec_off['t3ver_swapmode'],$rec_on['uid']); 00662 } 00663 $mainCell = str_replace('###SUB_ELEMENTS###', $subElements['on'], $mainCell); 00664 00665 // Create version element: 00666 $versionsInOtherWS = $this->versionsInOtherWS($table, $rec_on['uid']); 00667 $versionsInOtherWSWarning = $versionsInOtherWS && $GLOBALS['BE_USER']->workspace!==0 ? '<br/>'.$this->doc->icons(2).'Other version(s) in workspace '.$versionsInOtherWS : ''; 00668 $multipleWarning = (!$mainCell && $GLOBALS['BE_USER']->workspace!==0? '<br/>'.$this->doc->icons(3).'<b>Multiple versions in same workspace!</b>' : ''); 00669 $verWarning = $warnAboutVersions || ($warnAboutVersions_nonPages && $GLOBALS['TCA'][$table]['ctrl']['versioning_followPages'])? '<br/>'.$this->doc->icons(3).'<b>Version inside version!</b>' : ''; 00670 $verElement = $icon. 00671 '<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'))).'">'. 00672 t3lib_BEfunc::getRecordTitle($table,$rec_off,TRUE). 00673 '</a>'. 00674 $versionsInOtherWSWarning. 00675 $multipleWarning. 00676 $verWarning; 00677 if ($diffCode) { 00678 $verElement = ' 00679 <table border="0" cellpadding="0" cellspacing="0" class="ver-verElement"> 00680 <tr> 00681 <td nowrap="nowrap" width="180">'.$verElement.' </td> 00682 <td class="c-diffCell">'.$diffCode.'</td> 00683 </tr> 00684 </table>'; 00685 } 00686 00687 // Create version cell: 00688 $verCell = ' 00689 <td align="center">'.$this->formatVerId($rec_off['t3ver_id']).'</td> 00690 <td nowrap="nowrap">'. 00691 $verElement. 00692 $subElements['off']. 00693 '</td>'; 00694 00695 // Compile table row: 00696 $tableRows[] = ' 00697 <tr class="bgColor4"> 00698 '.$mainCell.$verCell.' 00699 <td nowrap="nowrap">'.$this->showStageChangeLog($table,$rec_off['uid'],$this->displayWorkspaceOverview_stageCmd($table,$rec_off)).'</td> 00700 <td nowrap="nowrap" class="'.$swapClass.'">'. 00701 $this->displayWorkspaceOverview_commandLinks($table,$rec_on,$rec_off,$vType). 00702 htmlspecialchars($swapLabel). 00703 '</td> 00704 <td nowrap="nowrap">'.htmlspecialchars($this->formatCount($rec_off['t3ver_count'])).'</td>'. // Lifecycle 00705 ($this->showWorkspaceCol ? ' 00706 <td nowrap="nowrap">'.htmlspecialchars($this->formatWorkspace($rec_off['t3ver_wsid'])).'</td>' : '').' 00707 </tr>'; 00708 00709 // Reset the main cell: 00710 $mainCell = ''; 00711 } 00712 } 00713 } 00714 } 00715 // Call recursively for sub-rows: 00716 $tableRows = $this->displayWorkspaceOverview_list($pArray[$k.'.'], $tableRows, $c+1, $warnAboutVersions_next); 00717 } 00718 } 00719 } 00720 return $tableRows; 00721 } 00722 00731 function displayWorkspaceOverview_pageTreeIconTitle($pageUid, $title, $indentCount) { 00732 $pRec = t3lib_BEfunc::getRecord('pages',$pageUid); 00733 return '<img src="clear.gif" width="1" height="1" hspace="'.($indentCount * $this->pageTreeIndent).'" align="top" alt="" />'. // Indenting page tree 00734 t3lib_iconWorks::getIconImage('pages',$pRec,$this->doc->backPath,' align="top" title="'.t3lib_BEfunc::getRecordIconAltText($pRec,'pages').'"'). 00735 htmlspecialchars(t3lib_div::fixed_lgd_cs($title,$this->pageTreeIndent_titleLgd)). 00736 ' '; 00737 } 00738 00746 function displayWorkspaceOverview_stageCmd($table,&$rec_off) { 00747 #debug($rec_off['t3ver_stage']); 00748 switch((int)$rec_off['t3ver_stage']) { 00749 case 0: 00750 $sId = 1; 00751 $sLabel = 'Editing'; // TODO Localize 00752 $color = '#666666'; // TODO Use CSS? 00753 $label = 'Comment for Reviewer:'; // TODO Localize 00754 $titleAttrib = 'Send to Review'; // TODO Localize 00755 break; 00756 case 1: 00757 $sId = 10; 00758 $sLabel = 'Review'; // TODO Localize 00759 $color = '#6666cc'; // TODO Use CSS? 00760 $label = 'Comment for Publisher:'; // TODO Localize 00761 $titleAttrib = 'Approve for Publishing'; // TODO Localize 00762 break; 00763 case 10: 00764 $sLabel = 'Publish'; // TODO Localize 00765 $color = '#66cc66'; // TODO Use CSS? 00766 break; 00767 case -1: 00768 $sLabel = $this->doc->icons(2).'Rejected'; // TODO Localize 00769 $sId = 0; 00770 $color = '#ff0000'; // TODO Use CSS? 00771 $label = 'Comment:'; // TODO Localize 00772 $titleAttrib = 'Reset stage'; // TODO Localize 00773 break; 00774 default: 00775 $sLabel = 'Undefined'; // TODO Localize 00776 $sId = 0; 00777 $color = ''; 00778 break; 00779 } 00780 #debug($sId); 00781 00782 $raiseOk = !$GLOBALS['BE_USER']->workspaceCannotEditOfflineVersion($table,$rec_off); 00783 00784 if ($raiseOk && $rec_off['t3ver_stage']!=-1) { 00785 // TODO Localize 00786 $onClick = 'var commentTxt=window.prompt("Please explain why you reject:",""); 00787 if (commentTxt!=null) {window.location.href="'.$this->doc->issueCommand( 00788 '&cmd['.$table.']['.$rec_off['uid'].'][version][action]=setStage'. 00789 '&cmd['.$table.']['.$rec_off['uid'].'][version][stageId]=-1' 00790 ).'&cmd['.$table.']['.$rec_off['uid'].'][version][comment]="+escape(commentTxt);}'. 00791 ' return false;'; 00792 // Reject: 00793 $actionLinks.= 00794 '<a href="#" onclick="'.htmlspecialchars($onClick).'">'. 00795 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/down.gif','width="14" height="14"').' alt="" align="top" title="Reject" />'. 00796 '</a>'; 00797 } else { 00798 // Reject: 00799 $actionLinks.= 00800 '<img src="'.$this->doc->backPath.'gfx/clear.gif" width="14" height="14" alt="" align="top" title="" />'; 00801 } 00802 00803 // TODO Use CSS? 00804 $actionLinks.= '<span style="background-color: '.$color.'; color: white;">'.$sLabel.'</span>'; 00805 00806 // Raise 00807 if ($raiseOk) { 00808 $onClick = 'var commentTxt=window.prompt("'.$label.'",""); 00809 if (commentTxt!=null) {window.location.href="'.$this->doc->issueCommand( 00810 '&cmd['.$table.']['.$rec_off['uid'].'][version][action]=setStage'. 00811 '&cmd['.$table.']['.$rec_off['uid'].'][version][stageId]='.$sId 00812 ).'&cmd['.$table.']['.$rec_off['uid'].'][version][comment]="+escape(commentTxt);}'. 00813 ' return false;'; 00814 if ($rec_off['t3ver_stage']!=10) { 00815 $actionLinks.= 00816 '<a href="#" onclick="'.htmlspecialchars($onClick).'">'. 00817 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/up.gif','width="14" height="14"').' alt="" align="top" title="'.htmlspecialchars($titleAttrib).'" />'. 00818 '</a>'; 00819 00820 $this->stageIndex[$sId][$table][] = $rec_off['uid']; 00821 } 00822 } 00823 00824 return $actionLinks; 00825 } 00826 00836 function displayWorkspaceOverview_commandLinks($table,&$rec_on,&$rec_off,$vType) { 00837 global $LANG; 00838 00839 if ($this->publishAccess && (!($GLOBALS['BE_USER']->workspaceRec['publish_access']&1) || (int)$rec_off['t3ver_stage']===10)) { 00840 $actionLinks = 00841 '<a href="'.htmlspecialchars($this->doc->issueCommand( 00842 '&cmd['.$table.']['.$rec_on['uid'].'][version][action]=swap'. 00843 '&cmd['.$table.']['.$rec_on['uid'].'][version][swapWith]='.$rec_off['uid'] 00844 )).'">'. 00845 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/insert1.gif','width="14" height="14"').' alt="" align="top" title="' . $LANG->getLL('img_title_publish') . '" />'. 00846 '</a>'; 00847 if ($GLOBALS['BE_USER']->workspaceSwapAccess() && (int)$rec_on['t3ver_state']!==1 && (int)$rec_off['t3ver_state']!==2) { 00848 $actionLinks.= 00849 '<a href="'.htmlspecialchars($this->doc->issueCommand( 00850 '&cmd['.$table.']['.$rec_on['uid'].'][version][action]=swap'. 00851 '&cmd['.$table.']['.$rec_on['uid'].'][version][swapWith]='.$rec_off['uid']. 00852 '&cmd['.$table.']['.$rec_on['uid'].'][version][swapIntoWS]=1' 00853 )).'">'. 00854 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/swap.png','width="14" height="14"').' alt="" align="top" title="' . $LANG->getLL('img_title_swap') . '" />'. 00855 '</a>'; 00856 } 00857 } 00858 00859 if (!$GLOBALS['BE_USER']->workspaceCannotEditOfflineVersion($table,$rec_off)) { 00860 00861 if ($GLOBALS['BE_USER']->workspace!==0) { 00862 // Release 00863 $confirm = $LANG->JScharCode($LANG->getLL('remove_from_ws_confirmation')); 00864 $actionLinks.= 00865 '<a href="'.htmlspecialchars($this->doc->issueCommand('&cmd['.$table.']['.$rec_off['uid'].'][version][action]=clearWSID')).'" onclick="return confirm(' . $confirm . ');">'. 00866 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/group_clear.gif','width="14" height="14"').' alt="" align="top" title="' . $LANG->getLL('img_title_remove_from_ws') . '" />'. 00867 '</a>'; 00868 } 00869 00870 // Edit 00871 if ($table==='pages' && $vType!=='element') { 00872 $tempUid = ($vType==='branch' || $GLOBALS['BE_USER']->workspace===0 ? $rec_off['uid'] : $rec_on['uid']); 00873 $actionLinks.= 00874 '<a href="#" onclick="top.loadEditId('.$tempUid.');top.goToModule(\''.$this->pageModule.'\'); return false;">'. 00875 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,t3lib_extMgm::extRelPath('cms').'layout/layout.gif','width="14" height="12"').' title="' . $LANG->getLL('img_title_edit_page') . '" alt="" />'. 00876 '</a>'; 00877 } else { 00878 $params = '&edit['.$table.']['.$rec_off['uid'].']=edit'; 00879 $actionLinks.= 00880 '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick($params,$this->doc->backPath)).'">'. 00881 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/edit2.gif','width="12" height="12"').' title="' . $LANG->getLL('img_title_edit_element') . '" alt="" />'. 00882 '</a>'; 00883 } 00884 } 00885 00886 // History/Log 00887 $actionLinks.= 00888 '<a href="'.htmlspecialchars($this->doc->backPath.'show_rechis.php?element='.rawurlencode($table.':'.$rec_off['uid']).'&returnUrl='.rawurlencode(t3lib_div::getIndpEnv('REQUEST_URI'))).'">'. 00889 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/history2.gif','width="13" height="12"').' title="' . $LANG->getLL('img_title_show_log') . '" alt="" />'. 00890 '</a>'; 00891 00892 // View 00893 if ($table==='pages') { 00894 $tempUid = ($vType==='branch' || $GLOBALS['BE_USER']->workspace===0 ? $rec_off['uid'] : $rec_on['uid']); 00895 $actionLinks.= 00896 '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($tempUid,$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($tempUid))).'">'. 00897 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/zoom.gif','width="12" height="12"').' title="" alt="" />'. 00898 '</a>'; 00899 } 00900 00901 return $actionLinks; 00902 } 00903 00912 function displayWorkspaceOverview_commandLinksSub($table,$rec,$origId) { 00913 global $LANG; 00914 00915 $uid = $rec['uid']; 00916 if ($origId || $GLOBALS['BE_USER']->workspace===0) { 00917 if (!$GLOBALS['BE_USER']->workspaceCannotEditRecord($table,$rec)) { 00918 // Edit 00919 if ($table==='pages') { 00920 $actionLinks.= 00921 '<a href="#" onclick="top.loadEditId('.$uid.');top.goToModule(\''.$this->pageModule.'\'); return false;">'. 00922 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,t3lib_extMgm::extRelPath('cms').'layout/layout.gif','width="14" height="12"').' title="' . $LANG->getLL('img_title_edit_page') . '" alt="" />'. 00923 '</a>'; 00924 } else { 00925 $params = '&edit['.$table.']['.$uid.']=edit'; 00926 $actionLinks.= 00927 '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick($params,$this->doc->backPath)).'">'. 00928 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/edit2.gif','width="12" height="12"').' title="' . $LANG->getLL('img_title_edit_element') . '" alt="" />'. 00929 '</a>'; 00930 } 00931 } 00932 00933 // History/Log 00934 $actionLinks.= 00935 '<a href="'.htmlspecialchars($this->doc->backPath.'show_rechis.php?element='.rawurlencode($table.':'.$uid).'&returnUrl='.rawurlencode(t3lib_div::getIndpEnv('REQUEST_URI'))).'">'. 00936 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/history2.gif','width="13" height="12"').' title="' . $LANG->getLL('img_title_show_log') . '" alt="" />'. 00937 '</a>'; 00938 } 00939 00940 // View 00941 if ($table==='pages') { 00942 $actionLinks.= 00943 '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($uid,$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($uid))).'">'. 00944 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/zoom.gif','width="12" height="12"').' title="" alt="" />'. 00945 '</a>'; 00946 } 00947 00948 return $actionLinks; 00949 } 00950 00962 function displayWorkspaceOverview_setInPageArray(&$pArray,$rlArr,$table,$row) { 00963 00964 // Initialize: 00965 ksort($rlArr); 00966 reset($rlArr); 00967 if (!$rlArr[0]['uid']) array_shift($rlArr); 00968 00969 // Get and remove first element in root line: 00970 $cEl = current($rlArr); 00971 $pUid = $cEl['t3ver_oid'] ? $cEl['t3ver_oid'] : $cEl['uid']; // Done to pile up "false versions" in the right branch... 00972 00973 $pArray[$pUid] = $cEl['title']; 00974 array_shift($rlArr); 00975 00976 // If there are elements left in the root line, call this function recursively (to build $pArray in depth) 00977 if (count($rlArr)) { 00978 if (!isset($pArray[$pUid.'.'])) $pArray[$pUid.'.'] = array(); 00979 $this->displayWorkspaceOverview_setInPageArray($pArray[$pUid.'.'],$rlArr,$table,$row); 00980 } else { // If this was the last element, set the value: 00981 $pArray[$pUid.'_'][$table][$row['t3ver_oid']][] = $row; 00982 } 00983 } 00984 00993 function subElements($uid,$treeLevel,$origId=0) { 00994 global $TCA; 00995 00996 if ($GLOBALS['BE_USER']->workspace===0 || !$this->MOD_SETTINGS['expandSubElements']) { // In online workspace we have a reduced view because otherwise it will bloat the listing: 00997 return '<br/> 00998 <img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/ol/joinbottom.gif','width="18" height="16"').' align="top" alt="" title="" />'. 00999 ($origId ? 01000 '<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'))).'">'. 01001 '<span class="typo3-dimmed"><em>[Sub elements, click for details]</em><span></a>' : 01002 '<span class="typo3-dimmed"><em>[Sub elements]</em><span>'); 01003 } else { // For an offline workspace, show sub elements: 01004 01005 $tCell = array(); 01006 01007 // Find records that follow pages when swapping versions: 01008 $recList = array(); 01009 foreach($TCA as $tN => $tCfg) { 01010 if ($tN!='pages' && ($treeLevel>0 || $TCA[$tN]['ctrl']['versioning_followPages'])) { 01011 $this->subElements_getNonPageRecords($tN, $uid, $recList); 01012 } 01013 } 01014 01015 // Render records collected above: 01016 $elCount = count($recList)-1; 01017 foreach($recList as $c => $comb) { 01018 list($tN,$rec) = $comb; 01019 01020 $this->subElements_renderItem( 01021 $tCell, 01022 $tN, 01023 $uid, 01024 $rec, 01025 $origId, 01026 $c==$elCount && $treeLevel==0 ? 1 : 0, // If true, will show bottom-join icon. 01027 '' 01028 ); 01029 } 01030 01031 // For branch, dive into the subtree: 01032 if ($treeLevel>0) { 01033 01034 // Drawing tree: 01035 $tree = t3lib_div::makeInstance('t3lib_pageTree'); 01036 $tree->init('AND '.$GLOBALS['BE_USER']->getPagePermsClause(1)); 01037 $tree->makeHTML = 2; // 2=Also rendering depth-data into the result array 01038 $tree->getTree($uid, 99, ''); 01039 01040 // Traverse page tree: 01041 foreach($tree->tree as $data) { 01042 01043 // Render page in table cell: 01044 $this->subElements_renderItem( 01045 $tCell, 01046 'pages', 01047 $uid, 01048 t3lib_BEfunc::getRecord('pages',$data['row']['uid']), // Needs all fields, at least more than what is given in $data['row']... 01049 $origId, 01050 2, // 2=the join icon and icon for the record is not rendered for pages (where all is in $data['HTML'] 01051 $data['HTML'] 01052 ); 01053 01054 // Find all records from page and collect in $recList: 01055 $recList = array(); 01056 foreach($TCA as $tN => $tCfg) { 01057 if ($tN!=='pages') { 01058 $this->subElements_getNonPageRecords($tN, $data['row']['uid'], $recList); 01059 } 01060 } 01061 01062 // Render records collected above: 01063 $elCount = count($recList)-1; 01064 foreach($recList as $c => $comb) { 01065 list($tN,$rec) = $comb; 01066 01067 $this->subElements_renderItem( 01068 $tCell, 01069 $tN, 01070 $uid, 01071 $rec, 01072 $origId, 01073 $c==$elCount?1:0, // If true, will show bottom-join icon. 01074 $data['HTML_depthData'] 01075 ); 01076 } 01077 } 01078 } 01079 01080 return ' 01081 <!-- Sub-element tree for versions --> 01082 <table border="0" cellpadding="0" cellspacing="1" class="ver-subtree"> 01083 '.implode('',$tCell).' 01084 </table>'; 01085 } 01086 } 01087 01096 function subElements_getNonPageRecords($tN, $uid, &$recList) { 01097 global $TCA; 01098 01099 $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows( 01100 '*', 01101 $tN, 01102 'pid='.intval($uid). 01103 ($TCA[$tN]['ctrl']['versioningWS'] ? ' AND t3ver_state=0' : ''). 01104 t3lib_BEfunc::deleteClause($tN), 01105 '', 01106 $TCA[$tN]['ctrl']['sortby'] ? $TCA[$tN]['ctrl']['sortby'] : $GLOBALS['TYPO3_DB']->stripOrderBy($TCA[$tN]['ctrl']['default_sortby']) 01107 ); 01108 01109 foreach($records as $rec) { 01110 $recList[] = array($tN,$rec); 01111 } 01112 } 01113 01126 function subElements_renderItem(&$tCell,$tN,$uid,$rec,$origId,$iconMode,$HTMLdata) { 01127 global $TCA; 01128 01129 // Initialize: 01130 $origUidFields = $TCA[$tN]['ctrl']['origUid']; 01131 $diffCode = ''; 01132 01133 if ($origUidFields) { // If there is a field for this table with original uids we will use that to connect records: 01134 if (!$origId) { // In case we are displaying the online originals: 01135 $this->targets['orig_'.$uid.'_'.$tN.'_'.$rec['uid']] = $rec; // Build up target array (important that 01136 $tdParams = ' id="orig_'.$uid.'_'.$tN.'_'.$rec['uid'].'" class="typo3-ver"'; // Setting ID of the table row 01137 } else { // Version branch: 01138 if ($this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]]) { // If there IS a corresponding original record...: 01139 01140 // Prepare Table row parameters: 01141 $tdParams = ' onmouseover="hlSubelements(\''.$origId.'_'.$tN.'_'.$rec[$origUidFields].'\', \''.$uid.'_'.$tN.'_'.$rec[$origUidFields].'\', 1, '.($this->MOD_SETTINGS['diff']==2?1:0).');"'. 01142 ' onmouseout="hlSubelements(\''.$origId.'_'.$tN.'_'.$rec[$origUidFields].'\', \''.$uid.'_'.$tN.'_'.$rec[$origUidFields].'\', 0, '.($this->MOD_SETTINGS['diff']==2?1:0).');"'. 01143 ' id="ver_'.$uid.'_'.$tN.'_'.$rec[$origUidFields].'" class="typo3-ver"'; 01144 01145 // Create diff view: 01146 if ($this->MOD_SETTINGS['diff']) { 01147 list($diffHTML,$diffPct) = $this->createDiffView($tN, $rec, $this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]]); 01148 01149 if ($this->MOD_SETTINGS['diff']==2) { 01150 $diffCode = 01151 ($diffPct ? '<span class="nobr">'.$diffPct.'% change</span>' : '-'). 01152 '<div style="visibility: hidden; position: absolute;" id="diff_'.$uid.'_'.$tN.'_'.$rec[$origUidFields].'" class="diffLayer">'. 01153 $diffHTML. 01154 '</div>'; 01155 } else { 01156 $diffCode = 01157 ($diffPct<0 ? 'N/A' : ($diffPct ? $diffPct.'% change:' : '')). 01158 $diffHTML; 01159 } 01160 } 01161 01162 // Unsetting the target fields allows us to mark all originals without a version in the subtree (see ->markupNewOriginals()) 01163 unset($this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]]); 01164 } else { // No original record, so must be new: 01165 $tdParams = ' class="typo3-ver-new"'; 01166 } 01167 } 01168 } else { // If no original uid column is supported for this table we are forced NOT to display any diff or highlighting. 01169 $tdParams = ' class="typo3-ver-noComp"'; 01170 } 01171 01172 // Compile the cell: 01173 $tCell[] = ' 01174 <tr'.$tdParams.'> 01175 <td class="iconTitle">'. 01176 $HTMLdata. 01177 ($iconMode < 2 ? 01178 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/ol/join'.($iconMode ? 'bottom' : '').'.gif','width="18" height="16"').' alt="" />'. 01179 t3lib_iconWorks::getIconImage($tN, $rec, $this->doc->backPath,'') : ''). 01180 t3lib_BEfunc::getRecordTitle($tN, $rec, TRUE). 01181 '</td> 01182 <td class="cmdCell">'. 01183 $this->displayWorkspaceOverview_commandLinksSub($tN,$rec,$origId). 01184 '</td>'.($origId ? '<td class="diffCell">'. 01185 $diffCode. 01186 '</td>':'').' 01187 </tr>'; 01188 } 01189 01195 function markupNewOriginals() { 01196 01197 if (count($this->targets)) { 01198 $scriptCode = ''; 01199 foreach($this->targets as $key => $rec) { 01200 $scriptCode.=' 01201 document.getElementById(\''.$key.'\').attributes.getNamedItem("class").nodeValue = \'typo3-ver-new\'; 01202 '; 01203 } 01204 01205 return $this->doc->wrapScriptTags($scriptCode); 01206 } 01207 } 01208 01217 function createDiffView($table, $diff_1_record, $diff_2_record) { 01218 global $TCA, $LANG; 01219 01220 // Initialize: 01221 $pctChange = 'N/A'; 01222 01223 // Check that records are arrays: 01224 if (is_array($diff_1_record) && is_array($diff_2_record)) { 01225 01226 // Load full table description and initialize diff-object: 01227 t3lib_div::loadTCA($table); 01228 $t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff'); 01229 01230 // Add header row: 01231 $tRows = array(); 01232 $tRows[] = ' 01233 <tr class="bgColor5 tableheader"> 01234 <td>' . $LANG->getLL('diffview_label_field_name') . '</td> 01235 <td width="98%" nowrap="nowrap">' . $LANG->getLL('diffview_label_colored_diff_view') . '</td> 01236 </tr> 01237 '; 01238 01239 // Initialize variables to pick up string lengths in: 01240 $allStrLen = 0; 01241 $diffStrLen = 0; 01242 01243 // Traversing the first record and process all fields which are editable: 01244 foreach($diff_1_record as $fN => $fV) { 01245 if ($TCA[$table]['columns'][$fN] && $TCA[$table]['columns'][$fN]['config']['type']!='passthrough' && !t3lib_div::inList('t3ver_label',$fN)) { 01246 01247 // Check if it is files: 01248 $isFiles = FALSE; 01249 if (strcmp(trim($diff_1_record[$fN]),trim($diff_2_record[$fN])) && 01250 $TCA[$table]['columns'][$fN]['config']['type']=='group' && 01251 $TCA[$table]['columns'][$fN]['config']['internal_type']=='file') { 01252 01253 // Initialize: 01254 $uploadFolder = $TCA[$table]['columns'][$fN]['config']['uploadfolder']; 01255 $files1 = array_flip(t3lib_div::trimExplode(',', $diff_1_record[$fN],1)); 01256 $files2 = array_flip(t3lib_div::trimExplode(',', $diff_2_record[$fN],1)); 01257 01258 // Traverse filenames and read their md5 sum: 01259 foreach($files1 as $filename => $tmp) { 01260 $files1[$filename] = @is_file(PATH_site.$uploadFolder.'/'.$filename) ? md5(t3lib_div::getUrl(PATH_site.$uploadFolder.'/'.$filename)) : $filename; 01261 } 01262 foreach($files2 as $filename => $tmp) { 01263 $files2[$filename] = @is_file(PATH_site.$uploadFolder.'/'.$filename) ? md5(t3lib_div::getUrl(PATH_site.$uploadFolder.'/'.$filename)) : $filename; 01264 } 01265 01266 // Implode MD5 sums and set flag: 01267 $diff_1_record[$fN] = implode(' ',$files1); 01268 $diff_2_record[$fN] = implode(' ',$files2); 01269 $isFiles = TRUE; 01270 } 01271 01272 // If there is a change of value: 01273 if (strcmp(trim($diff_1_record[$fN]),trim($diff_2_record[$fN]))) { 01274 01275 01276 // Get the best visual presentation of the value and present that: 01277 $val1 = t3lib_BEfunc::getProcessedValue($table,$fN,$diff_2_record[$fN],0,1); 01278 $val2 = t3lib_BEfunc::getProcessedValue($table,$fN,$diff_1_record[$fN],0,1); 01279 01280 // Make diff result and record string lenghts: 01281 $diffres = $t3lib_diff_Obj->makeDiffDisplay($val1,$val2,$isFiles?'div':'span'); 01282 $diffStrLen+= $t3lib_diff_Obj->differenceLgd; 01283 $allStrLen+= strlen($val1.$val2); 01284 01285 // If the compared values were files, substituted MD5 hashes: 01286 if ($isFiles) { 01287 $allFiles = array_merge($files1,$files2); 01288 foreach($allFiles as $filename => $token) { 01289 if (strlen($token)==32 && strstr($diffres,$token)) { 01290 $filename = 01291 t3lib_BEfunc::thumbCode(array($fN=>$filename),$table,$fN,$this->doc->backPath). 01292 $filename; 01293 $diffres = str_replace($token,$filename,$diffres); 01294 } 01295 } 01296 } 01297 01298 // Add table row with result: 01299 $tRows[] = ' 01300 <tr class="bgColor4"> 01301 <td>'.htmlspecialchars($GLOBALS['LANG']->sL(t3lib_BEfunc::getItemLabel($table,$fN))).'</td> 01302 <td width="98%">'.$diffres.'</td> 01303 </tr> 01304 '; 01305 } else { 01306 // Add string lengths even if value matched - in this was the change percentage is not high if only a single field is changed: 01307 $allStrLen+=strlen($diff_1_record[$fN].$diff_2_record[$fN]); 01308 } 01309 } 01310 } 01311 01312 // Calculate final change percentage: 01313 $pctChange = $allStrLen ? ceil($diffStrLen*100/$allStrLen) : -1; 01314 01315 // Create visual representation of result: 01316 if (count($tRows)>1) { 01317 $content.= '<table border="0" cellpadding="1" cellspacing="1" class="diffTable">'.implode('',$tRows).'</table>'; 01318 } else { 01319 $content.= '<span class="nobr">'.$this->doc->icons(1).$LANG->getLL('diffview_complete_match').'</span>'; 01320 } 01321 } else $content.= $this->doc->icons(3).$LANG->getLL('diffview_cannot_find_records'); 01322 01323 // Return value: 01324 return array($content,$pctChange); 01325 } 01326 01327 01328 01329 01330 01331 01332 01333 01334 01335 01336 01337 01338 /******************************** 01339 * 01340 * Module content: Workspace list 01341 * 01342 ********************************/ 01343 01349 function moduleContent_workspaceList() { 01350 // Original Kasper's TODO: Workspace listing 01351 // 01352 // - LISTING: Shows list of available workspaces for user. Used can see title, description, publication time, freeze-state, db-mount, member users/groups etc. Current workspace is indicated. 01353 // - SWITCHING: Switching between available workspaces is done by a button shown for each in the list 01354 // - ADMIN: Administrator of a workspace can click an edit-button linking to a form where he can edit the workspace. Users and groups should be selected based on some filtering so he cannot select groups he is not a member off himself (or some other rule... like for permission display with blinded users/groups) 01355 // - CREATE: If allowed, the user can create a new workspace which brings up a form where he can enter basic data. This is saved by a local instance of tcemain with forced admin-rights (creation in pid=0!). 01356 return $this->workspaceList_displayUserWorkspaceList(); 01357 } 01358 01364 function workspaceList_displayUserWorkspaceList() { 01365 global $BACK_PATH, $LANG; 01366 01367 // table header 01368 $content = $this->workspaceList_displayUserWorkspaceListHeader(); 01369 01370 // get & walk workspace list generating content 01371 $wkspList = $this->workspaceList_getUserWorkspaceList(); 01372 $rowNum = 1; 01373 foreach ($wkspList as $wksp) { 01374 $currentWksp = ($GLOBALS['BE_USER']->workspace == $wksp['uid']); 01375 01376 // Each workspace data occupies two rows: 01377 // (1) Folding + Icons + Title + Description 01378 // (2) Information about workspace (initially hidden) 01379 01380 $cssClass = ($currentWksp ? 'bgColor3' : 'bgColor4'); 01381 // Start first row 01382 $content .= '<tr class="' . $cssClass . '">'; 01383 01384 // row #1, column #1: expand icon 01385 $content .= '<td>' . 01386 '<a href="javascript:expandCollapse(' . $rowNum . ')">' . 01387 '<img ' . t3lib_iconWorks::skinImg($BACK_PATH, 'gfx/ol/plusbullet.gif', 'width="18" height="16"') . ' id="wl_' . $rowNum . 'i" border="0" hspace="1" alt="' . $LANG->getLL('img_title_show_more') . '" />' . 01388 '</a></td>'; 01389 01390 // row #1, column #2: icon panel 01391 $content .= '<td nowrap="nowrap">'; // Mozilla Firefox will attempt wrap due to `width="1"` on topmost column 01392 $content .= $this->workspaceList_displayIcons($currentWksp, $wksp); 01393 $content .= '</td>'; 01394 01395 // row #1, column #3: current workspace indicator 01396 $content .= '<td nowrap="nowrap" style="text-align: center">'; // Mozilla Firefox will attempt wrap due to `width="1"` on topmost column 01397 $content .= (!$currentWksp ? ' ' : '<img ' . t3lib_iconWorks::skinImg($BACK_PATH, 'gfx/icon_ok.gif', 'width="18" height="16"') . ' id="wl_' . $rowNum . 'i" border="0" hspace="1" alt="' . $LANG->getLL('img_title_current_workspace') . '" />'); 01398 $content .= '</td>'; 01399 01400 // row #1, column #4 and 5: title and description 01401 $content .= '<td nowrap="nowrap">' . $wksp['title'] . '</td>' . 01402 '<td>' . nl2br($wksp['description']) . '</td>'; 01403 $content .= '</tr>'; 01404 01405 // row #2, column #1 and #2 01406 $content .= '<tr id="wl_' . $rowNum . '" class="bgColor" style="display: none">'; 01407 $content .= '<td colspan="2" style="border-right: none;"> </td>'; 01408 01409 // row #2, column #3, #4 and #4 01410 $content .= '<td colspan="3" style="border-left: none;">' . 01411 $this->workspaceList_formatWorkspaceData($wksp) . 01412 '</td>'; 01413 01414 $content .= '</tr>'; 01415 $rowNum++; 01416 } 01417 $content .= '</table>'; 01418 01419 $newWkspUrl = 'workspaceforms.php?action=new'; 01420 01421 // workspace creation link 01422 if ($GLOBALS['BE_USER']->isAdmin() || 0 != ($GLOBALS['BE_USER']->groupData['workspace_perms'] & 4)) { 01423 $content .= '<br /><a href="' . $newWkspUrl . '">' . 01424 '<img ' . 01425 t3lib_iconWorks::skinImg($BACK_PATH, 'gfx/new_el.gif', 'width="11" height="12"') . 01426 ' alt="' . $LANG->getLL('img_title_create_new_workspace'). '" id="ver-wl-new-workspace-icon" />' . 01427 $LANG->getLL('link_text_create_new_workspace') . '</a>'; 01428 } 01429 return $content; 01430 } 01431 01432 01433 01434 01435 01441 function workspaceList_getUserWorkspaceList() { 01442 // Get BE users if necessary 01443 if (!is_array($this->be_user_Array)) { 01444 $this->be_user_Array = t3lib_BEfunc::getUserNames(); 01445 } 01446 // Get list of all workspaces. Note: system workspaces will be always displayed before custom ones! 01447 $workspaces = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*','sys_workspace','pid=0'.t3lib_BEfunc::deleteClause('sys_workspace'),'','title'); 01448 $availableWorkspaces = array(); 01449 01450 // Live 01451 $wksp = $this->workspaceList_createFakeWorkspaceRecord(0); 01452 $wksp = $GLOBALS['BE_USER']->checkWorkspace($wksp); 01453 if (false !== $wksp) { 01454 $availableWorkspaces[] = $wksp; 01455 } 01456 01457 // Draft 01458 $wksp = $this->workspaceList_createFakeWorkspaceRecord(-1); 01459 $wksp = $GLOBALS['BE_USER']->checkWorkspace($wksp); 01460 if (false !== $wksp) { 01461 $availableWorkspaces[] = $wksp; 01462 } 01463 01464 // Custom 01465 foreach($workspaces as $rec) { 01466 // see if user can access this workspace in any way 01467 if (false !== ($result = $GLOBALS['BE_USER']->checkWorkspace($rec))) { 01468 $availableWorkspaces[] = $result; // `$result` contains `$rec` plus access type through '_ACCESS' key 01469 } 01470 } 01471 return $availableWorkspaces; 01472 } 01473 01483 function workspaceList_formatWorkspaceData(&$wksp) { 01484 global $LANG; 01485 01486 $content = '<table cellspacing="1" cellpadding="1" width="100%" class="ver-wl-details-table">' . 01487 '<tr><td class="ver-wl-details-label"><b>' . $LANG->getLL('workspace_list_label_file_mountpoints') . '</b></td>' . 01488 '<td class="ver-wl-details">' . $this->workspaceList_getFileMountPoints($wksp) . '</td></tr>' . 01489 '<tr><td class="ver-wl-details-label"><b>' . $LANG->getLL('workspace_list_label_db_mountpoints') . '</b></td>' . 01490 '<td class="ver-wl-details">' . $this->workspaceList_getWebMountPoints($wksp) . '</td></tr>'; 01491 if ($wksp['uid'] > 0) { 01492 // Displaying information below makes sence only for custom workspaces 01493 $content .= 01494 '<tr><td class="ver-wl-details-label"><b>' . $LANG->getLL('workspace_list_label_frozen') . '</b></td>' . 01495 '<td class="ver-wl-details">' . $LANG->getLL($wksp['freeze'] ? 'workspace_list_label_frozen_yes' : 'workspace_list_label_frozen_no') . '</td></tr>' . 01496 '<tr><td class="ver-wl-details-label"><b>' . $LANG->getLL('workspace_list_label_publish_date') . '</b></td>' . 01497 '<td class="ver-wl-details">' . ($wksp['publish_time'] == 0 ? ' –' : t3lib_BEfunc::datetime($wksp['publish_time'])) . '</td></tr>' . 01498 '<tr><td class="ver-wl-details-label"><b>' . $LANG->getLL('workspace_list_label_unpublish_date') . '</b></td>' . 01499 '<td class="ver-wl-details">' . ($wksp['unpublish_time'] == 0 ? ' –' : t3lib_BEfunc::datetime($wksp['unpublish_time'])) . '</td></tr>' . 01500 '<tr><td class="ver-wl-details-label"><b>' . $LANG->getLL('workspace_list_label_your_access') . '</b></td>' . 01501 '<td class="ver-wl-details">' . $LANG->getLL('workspace_list_access_' . $wksp['_ACCESS']) . '</td></tr>' . 01502 '<tr><td class="ver-wl-details-label"><b>' . $LANG->getLL('workspace_list_label_workspace_users') . '</b></td>' . 01503 '<td class="ver-wl-details">' . $this->workspaceList_getUserList($wksp) . '</td></tr>'; 01504 } 01505 else if ($GLOBALS['BE_USER']->isAdmin()) { 01506 // show users for draft/live workspace only to admin users 01507 $content .= '<tr><td class="ver-wl-details-label"><b>' . $LANG->getLL('workspace_list_label_workspace_users') . '</b></td>' . 01508 '<td class="ver-wl-details">' . $this->workspaceList_getUserList($wksp) . '</td></tr>'; 01509 } 01510 $content .= '</table>'; 01511 01512 return $content; 01513 } 01514 01515 01516 01517 01518 01525 function workspaceList_getWebMountPoints(&$wksp) { 01526 if ($wksp['uid'] <= 0) { 01527 // system workspaces 01528 return $GLOBALS['LANG']->getLL($wksp['uid'] == 0 ? 'workspace_list_db_mount_point_live' : 'workspace_list_db_mount_point_draft'); 01529 } 01530 01531 // here only if obtaining mount points for custom workspaces 01532 01533 // Warning: all fields needed for t3lib_iconWorks::getIconImage()! 01534 $MPs = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'pages', 'deleted=0 AND uid IN (' . $GLOBALS['TYPO3_DB']->cleanIntList($wksp['db_mountpoints']) . ')', '', 'title'); 01535 $content_array = array(); 01536 if (count($MPs) > 0) { 01537 $isAdmin = $GLOBALS['BE_USER']->isAdmin(); 01538 if (!$isAdmin) { 01539 // We need to fetch user's mount point list (including MPS mounted from groups). 01540 // This list must not be affects by current user's workspace. It means we cannot use 01541 // $BE_USER->isInWebMount() to check mount points. 01542 $userMPs = explode(',', $GLOBALS['BE_USER']->dataLists['webmount_list']); // includes group data if necessary! 01543 } 01544 foreach ($MPs as $mp) { 01545 if (!$isAdmin && !in_array($mp['uid'], $userMPs)) { 01546 // Show warning icon 01547 $title = $GLOBALS['LANG']->getLL('workspace_list_mount_point_inaccessible'); 01548 $str = '<img ' . t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'], 'gfx/icon_warning.gif', 'width="18" height="16"') . 01549 ' alt="' . $title . '" title="' . $title . '" align="absmiddle" />'; 01550 $classAttr = 'class="ver-wl-mp-inacessible" '; 01551 } 01552 else { 01553 // normal icon 01554 $str = t3lib_iconWorks::getIconImage('pages', $mp, $GLOBALS['BACK_PATH'], ' align="absmiddle"'); 01555 $classAttr = ''; 01556 } 01557 // Will show UID on hover. Just convinient to user. 01558 $content_array[] = $str . '<span ' . $classAttr . 'title="UID: ' . $mp['uid'] . '">' . $mp['title'] . '</span>'; 01559 } 01560 } 01561 if (count($content_array) > 0) { 01562 return implode('<br />', $content_array); 01563 } 01564 // no mount points 01565 return $GLOBALS['LANG']->getLL('workspace_list_db_mount_point_custom'); 01566 } 01567 01574 function workspaceList_getFileMountPoints(&$wksp) { 01575 if ($wksp['uid'] == -1) { 01576 // draft workspace - none! 01577 return $GLOBALS['LANG']->getLL('workspace_list_file_mount_point_draft'); 01578 } 01579 else if ($wksp['uid'] == 0) { 01580 // live workspace 01581 return $GLOBALS['LANG']->getLL('workspace_list_file_mount_point_live'); 01582 } 01583 01584 // Here if displaying information for custom workspace 01585 01586 // Warning: all fields needed for t3lib_iconWorks::getIconImage()! 01587 $MPs = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'sys_filemounts', 'deleted=0 AND hidden=0 AND uid IN (' . $GLOBALS['TYPO3_DB']->cleanIntList($wksp['file_mountpoints']) . ')', '', 'title'); 01588 if (count($MPs) != 0) { 01589 // Has mount points 01590 $isAdmin = $GLOBALS['BE_USER']->isAdmin(); 01591 if (!$isAdmin) { 01592 // We need to fetch user's mount point list (including MPS mounted from groups). 01593 // This list must not be affects by current user's workspace. It means we cannot use 01594 // $BE_USER->isInWebMount() to check mount points. 01595 $userMPs = explode(',', $GLOBALS['BE_USER']->dataLists['filemount_list']); // includes group data if necessary! 01596 } 01597 foreach ($MPs as $mp) { 01598 if (!$isAdmin && !in_array($mp['uid'], $userMPs)) { 01599 // Show warning icon 01600 $title = $GLOBALS['LANG']->getLL('workspace_list_mount_point_inaccessible'); 01601 $str = '<img ' . t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'], 'gfx/icon_warning.gif', 'width="18" height="16"') . 01602 ' alt="' . $title . '" title="' . $title . '" align="absmiddle" />'; 01603 $classAttr = 'class="ver-wl-mp-inacessible" '; 01604 } 01605 else { 01606 // normal icon 01607 $str = t3lib_iconWorks::getIconImage('sys_filemounts', $mp, $GLOBALS['BACK_PATH'], ' align="absmiddle"'); 01608 $classAttr = ''; 01609 } 01610 // Will show UID on hover. Just convinient to user. 01611 $content_array[] = $str . '<span ' . $classAttr . 'title="UID: ' . $mp['uid'] . '">' . $mp['title'] . '</span>'; 01612 } 01613 } 01614 if (count($content_array) > 0) { 01615 return implode('<br />', $content_array); 01616 } 01617 // No file mount points 01618 return $GLOBALS['LANG']->getLL('workspace_list_file_mount_point_custom'); 01619 } 01620 01627 function workspaceList_displayUserWorkspaceListHeader() { 01628 global $LANG; 01629 // TODO CSH lables? 01630 return '<table border="0" cellpadding="0" cellspacing="1" class="lrPadding workspace-overview ver-wl-table"> 01631 <tr class="bgColor5 tableheader"> 01632 <td width="1"> </td> 01633 <td width="1"> </td> 01634 <td nowrap="nowrap">' . $LANG->getLL('workspace_list_label_current_workspace') . '</td> 01635 <td nowrap="nowrap">' . $LANG->getLL('workspace_list_label_workspace_title') . '</td> 01636 <td nowrap="nowrap">' . $LANG->getLL('workspace_list_label_workspace_description') . '</td> 01637 </tr>'; 01638 } 01639 01640 01647 function workspaceList_getUserList(&$wksp) { 01648 global $LANG; 01649 01650 if ($wksp['uid'] > 0) { 01651 // custom workspaces 01652 $content = $this->workspaceList_getUserListWithAccess($wksp['adminusers'], $LANG->getLL('workspace_list_label_owners')); // owners 01653 $content .= $this->workspaceList_getUserListWithAccess($wksp['members'], $LANG->getLL('workspace_list_label_members')); // members 01654 $content .= $this->workspaceList_getUserListWithAccess($wksp['reviewers'], $LANG->getLL('workspace_list_label_reviewers')); // reviewers 01655 if ($content != '') { 01656 $content = '<table cellpadding="0" cellspacing="1" width="100%" class="lrPadding workspace-overview">' . $content . '</table>'; 01657 } else { 01658 $content = $LANG->getLL($wksp['uid'] > 0 ? 'workspace_list_access_admins_only' : 'workspace_list_access_anyone'); 01659 } 01660 } 01661 else { 01662 // live and draft workspace 01663 $content = $this->workspaceList_getUserListForSysWorkspace($wksp); 01664 } 01665 return $content; 01666 } 01667 01674 function workspaceList_getUserListForSysWorkspace(&$wksp) { 01675 $option = ($wksp['uid'] == 0 ? 1 : 2); 01676 $content_array = array(); 01677 foreach ($this->be_user_Array_full as $uid => $user) { 01678 if ($user['admin'] != 0 || 0 != ($user['workspace_perms'] & $option)) { 01679 if ($uid == $GLOBALS['BE_USER']->user['uid']) { 01680 // highlight current user 01681 $tag0 = '<span class="ver-wl-current-user">'; 01682 $tag1 = '</span>'; 01683 } 01684 else { 01685 $tag0 = $tag1 = ''; 01686 } 01687 $content_array[] = t3lib_iconWorks::getIconImage('be_users', $uid, $GLOBALS['BACK_PATH'], ' align="middle" alt="UID: ' . $uid . '"') . 01688 $tag0 . $user['username'] . $tag1; 01689 } 01690 } 01691 return implode('<br />', $content_array); 01692 } 01693 01701 function workspaceList_getUserListWithAccess(&$list, $access) { 01702 $content_array = array(); 01703 if ($list != '') { 01704 $userIDs = explode(',', $list); 01705 01706 // get user names and sort 01707 $regExp = '/^(be_[^_]+)_(\d+)$/'; 01708 $groups = false; 01709 foreach ($userIDs as $userUID) { 01710 $id = $userUID; 01711 01712 if (preg_match($regExp, $userUID)) { 01713 $table = preg_replace($regExp, '\1', $userUID); 01714 $id = intval(preg_replace($regExp, '\2', $userUID)); 01715 if ($table == 'be_users') { 01716 // user 01717 $icon = $GLOBALS['TCA']['be_users']['typeicons'][$this->be_user_Array[$id]['admin']]; 01718 if ($id == $GLOBALS['BE_USER']->user['uid']) { 01719 // highlight current user 01720 $tag0 = '<span class="ver-wl-current-user">'; 01721 $tag1 = '</span>'; 01722 } 01723 else { 01724 $tag0 = $tag1 = ''; 01725 } 01726 $content_array[] = t3lib_iconWorks::getIconImage($table, $this->be_user_Array[$id], $GLOBALS['BACK_PATH'], ' align="middle" alt="UID: ' . $id . '"') . 01727 $tag0 . $this->be_user_Array_full[$id]['username'] . $tag1; 01728 } 01729 else { 01730 // group 01731 if (false === $groups) { 01732 $groups = t3lib_BEfunc::getGroupNames(); 01733 } 01734 $content_array[] = t3lib_iconWorks::getIconImage($table, $groups[$id], $GLOBALS['BACK_PATH'], ' align="middle" alt="UID: ' . $id . '"') . 01735 $groups[$id]['title']; 01736 } 01737 } 01738 else { 01739 // user id 01740 if ($userUID == $GLOBALS['BE_USER']->user['uid']) { 01741 // highlight current user 01742 $tag0 = '<span class="ver-wl-current-user">'; 01743 $tag1 = '</span>'; 01744 } 01745 else { 01746 $tag0 = $tag1 = ''; 01747 } 01748 $content_array[] = t3lib_iconWorks::getIconImage('be_users', $this->be_user_Array[$id], $GLOBALS['BACK_PATH'], ' align="middle" alt="UID: ' . $id . '"') . 01749 $tag0 . $this->be_user_Array_full[$userUID]['username'] . $tag1; 01750 } 01751 } 01752 sort($content_array); 01753 } 01754 else { 01755 $content_array[] = ' –'; 01756 } 01757 01758 $content = '<tr><td class="ver-wl-details-label ver-wl-details-user-list-label">'; 01759 // TODO CSH lable explaining access here? 01760 $content .= '<b>' . $access . '</b></td>'; 01761 $content .= '<td class="ver-wl-details">' . implode('<br />', $content_array) . '</td></tr>'; 01762 return $content; 01763 } 01764 01765 01766 01774 function workspaceList_displayIcons($currentWorkspace, &$wksp) { 01775 global $BACK_PATH, $LANG; 01776 01777 $content = ''; 01778 // `edit workspace` button 01779 if ($this->workspaceList_hasEditAccess($wksp)) { 01780 // User can modify workspace parameters, display corresponding link and icon 01781 $editUrl = 'workspaceforms.php?action=edit&wkspId=' . $wksp['uid']; 01782 01783 $content .= '<a href="' . $editUrl . '" />' . 01784 '<img ' . t3lib_iconWorks::skinImg($BACK_PATH, 'gfx/edit2.gif', 'width="11" height="12"') . ' border="0" alt="' . $LANG->getLL('workspace_list_icon_title_edit_workspace') . '" align="middle" hspace="1" />' . 01785 '</a>'; 01786 } else { 01787 // User can NOT modify workspace parameters, display space 01788 // Get only withdth and height from skinning API 01789 $content .= '<img src="clear.gif" ' . 01790 t3lib_iconWorks::skinImg($BACK_PATH, 'gfx/edit2.gif', 'width="11" height="12"', 2) . 01791 ' border="0" alt="" hspace="1" align="middle" />'; 01792 } 01793 // `switch workspace` button 01794 if (!$currentWorkspace) { 01795 // Workspace switching button 01796 $content .= '<a href="' . 01797 t3lib_div::getIndpEnv('SCRIPT_NAME') . 01798 '?changeWorkspace=' . $wksp['uid'] . '"/>' . 01799 '<img ' . t3lib_iconWorks::skinImg($BACK_PATH, 'gfx/switch.gif', 'width="11" height="10"') . ' border="0" alt="' . $LANG->getLL('workspace_list_icon_title_switch_workspace') . '" align="middle" hspace="1" />' . 01800 '</a>'; 01801 } else { 01802 // Current workspace: empty space instead of workspace switching button 01803 // 01804 // Here get only width and height from skinning API 01805 $content .= '<img src="clear.gif" ' . 01806 t3lib_iconWorks::skinImg($BACK_PATH, 'gfx/switch.png', 'width="18" height="16"', 2) . 01807 ' border="0" alt="" hspace="1" align="middle" alt="" />'; 01808 } 01809 return $content; 01810 } 01811 01822 function workspaceList_hasEditAccess(&$wksp) { 01823 $access = &$wksp['_ACCESS']; 01824 return ($wksp['uid'] > 0 && ($access == 'admin' || $access == 'owner')); 01825 } 01826 01834 function workspaceList_createFakeWorkspaceRecord($uid) { 01835 global $BE_USER; 01836 01837 $record = array( 01838 'uid' => $uid, 01839 'pid' => 0, // always 0! 01840 'tstamp' => 0, // does not really matter 01841 'deleted' => 0, 01842 // TODO Localize all strings below 01843 'title' => ($uid == 0 ? '[Live workspace]' : '[Draft workspace]'), // TODO Localize this! 01844 // TODO Localize all strings below 01845 'description' => ($uid == 0 ? 'Live workspace' : 'Draft workspace'), // TODO Localize this! 01846 'adminusers' => '', 01847 'members' => '', 01848 'reviewers' => '', 01849 'db_mountpoints' => '', // TODO get mount points from user profile 01850 'file_mountpoints' => '', // TODO get mount points from user profile for live workspace only (uid == 0) 01851 'publish_time' => 0, 01852 'unpublish_time' => 0, 01853 'freeze' => 0, 01854 'live_edit' => ($uid == 0), 01855 'vtypes' => 0, 01856 'disable_autocreate' => 0, 01857 'swap_modes' => 0, 01858 'publish_access' => 0, 01859 'stagechg_notification' => 0 01860 ); 01861 return $record; 01862 } 01863 01864 01865 01866 01867 01868 01869 01870 01871 01872 01873 01874 01875 01876 01877 01878 01879 01880 01881 01882 01883 01884 01885 01886 01887 /************************************** 01888 * 01889 * Helper functions 01890 * 01891 *************************************/ 01892 01899 function formatVerId($verId) { 01900 return '1.'.$verId; 01901 } 01902 01909 function formatWorkspace($wsid) { 01910 01911 // Render, if not cached: 01912 if (!isset($this->formatWorkspace_cache[$wsid])) { 01913 switch($wsid) { 01914 case -1: 01915 $this->formatWorkspace_cache[$wsid] = '[Draft]'; 01916 break; 01917 case 0: 01918 $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... 01919 break; 01920 default: 01921 list($titleRec) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('title','sys_workspace','uid='.intval($wsid).t3lib_BEfunc::deleteClause('sys_workspace')); 01922 $this->formatWorkspace_cache[$wsid] = '['.$wsid.'] '.$titleRec['title']; 01923 break; 01924 } 01925 } 01926 01927 return $this->formatWorkspace_cache[$wsid]; 01928 } 01929 01936 function formatCount($count) { 01937 global $LANG; 01938 01939 // Render, if not cached: 01940 if (!isset($this->formatCount_cache[$count])) { 01941 switch($count) { 01942 case 0: 01943 $this->formatCount_cache[$count] = $LANG->getLL('workspace_list_publishing_count_draft'); 01944 break; 01945 case 1: 01946 $this->formatCount_cache[$count] = $LANG->getLL('workspace_list_publishing_count_archive'); 01947 break; 01948 default: 01949 $this->formatCount_cache[$count] = sprintf($LANG->getLL('workspace_list_publishing_count'), $count); 01950 break; 01951 } 01952 } 01953 01954 return $this->formatCount_cache[$count]; 01955 } 01956 01964 function versionsInOtherWS($table,$uid) { 01965 01966 // Check for duplicates: 01967 // Select all versions of record NOT in this workspace: 01968 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows( 01969 't3ver_wsid', 01970 $table, 01971 'pid=-1 01972 AND t3ver_oid='.intval($uid).' 01973 AND t3ver_wsid!='.intval($GLOBALS['BE_USER']->workspace).' 01974 AND (t3ver_wsid=-1 OR t3ver_wsid>0)'. 01975 t3lib_BEfunc::deleteClause($table), 01976 '', 01977 't3ver_wsid', 01978 '', 01979 't3ver_wsid' 01980 ); 01981 if (count($rows)) { 01982 return implode(',',array_keys($rows)); 01983 } 01984 } 01985 01994 function showStageChangeLog($table,$id,$stageCommands) { 01995 global $LANG; 01996 01997 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows( 01998 'log_data,tstamp,userid', 01999 'sys_log', 02000 'action=6 and details_nr=30 02001 AND tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table,'sys_log').' 02002 AND recuid='.intval($id) 02003 ); 02004 02005 $entry = array(); 02006 foreach($rows as $dat) { 02007 $data = unserialize($dat['log_data']); 02008 $username = $this->be_user_Array[$dat['userid']] ? $this->be_user_Array[$dat['userid']]['username'] : '['.$dat['userid'].']'; 02009 02010 switch($data['stage']) { 02011 case 1: 02012 $text = $LANG->getLL('stage_sent_to_review'); 02013 break; 02014 case 10: 02015 $text = $LANG->getLL('stage_approved_for_publish'); 02016 break; 02017 case -1: 02018 $text = $LANG->getLL('stage_rejected'); 02019 break; 02020 case 0: 02021 $text = $LANG->getLL('stage_reset_to_editing'); 02022 break; 02023 default: 02024 $text = $LANG->getLL('stage_undefined'); 02025 break; 02026 } 02027 $text = t3lib_BEfunc::datetime($dat['tstamp']).': ' . sprintf($text, $username); 02028 $text.= ($data['comment']?'<br/>' . $LANG->getLL('stage_label_user_comment'). ' <em>'.$data['comment'].'</em>':''); 02029 02030 $entry[] = $text; 02031 } 02032 02033 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>'. 02034 '<div class="logLayer" style="visibility: hidden; position: absolute;" id="log_'.$table.$id.'">'.implode('<hr/>',$entry).'</div>' : $stageCommands; 02035 } 02036 02037 02038 02039 02040 02041 02042 02043 02044 /********************************** 02045 * 02046 * Processing 02047 * 02048 **********************************/ 02049 02055 function publishAction() { 02056 02057 // If "Publish" or "Swap" buttons are pressed: 02058 if (t3lib_div::_POST('_publish') || t3lib_div::_POST('_swap')) { 02059 02060 // Initialize workspace object and request all pending versions: 02061 $wslibObj = t3lib_div::makeInstance('wslib'); 02062 $cmd = $wslibObj->getCmdArrayForPublishWS($GLOBALS['BE_USER']->workspace, t3lib_div::_POST('_swap')); 02063 02064 // Execute the commands: 02065 $tce = t3lib_div::makeInstance('t3lib_TCEmain'); 02066 $tce->stripslashes_values = 0; 02067 $tce->start(array(), $cmd); 02068 $tce->process_cmdmap(); 02069 02070 return $tce->errorLog; 02071 } 02072 } 02073 } 02074 02075 // Include extension? 02076 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/mod/user/ws/index.php']) { 02077 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/mod/user/ws/index.php']); 02078 } 02079 02080 02081 02082 02083 02084 02085 02086 02087 02088 // Make instance: 02089 $SOBE = t3lib_div::makeInstance('SC_mod_user_ws_index'); 02090 $SOBE->init(); 02091 $SOBE->main(); 02092 $SOBE->printContent(); 02093 ?>