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