git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@2471 709f56b5-9817-0410-a4d7...
[Packages/TYPO3.CMS.git] / typo3 / sysext / version / cm1 / index.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2004-2005 Kasper Skaarhoj (kasperYYYY@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 *
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
24 /**
25 * Versioning module
26 *
27 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
28 */
29 /**
30 * [CLASS/FUNCTION INDEX of SCRIPT]
31 *
32 *
33 *
34 * 102: class tx_version_cm1 extends t3lib_SCbase
35 *
36 * SECTION: Standard module initialization
37 * 138: function menuConfig()
38 * 175: function main()
39 * 236: function jumpToUrl(URL)
40 * 296: function printContent()
41 *
42 * SECTION: Versioning management
43 * 322: function versioningMgm()
44 * 485: function pageSubContent($pid,$c=0)
45 * 539: function lookForOwnVersions($table,$uid)
46 * 556: function adminLinks($table,$row)
47 *
48 * SECTION: Workspace management
49 * 628: function workspaceMgm()
50 * 688: function displayWorkspaceOverview()
51 * 758: function displayWorkspaceOverview_list($pArray)
52 * 923: function displayWorkspaceOverview_setInPageArray(&$pArray,$table,$row)
53 * 936: function displayWorkspaceOverview_allStageCmd()
54 *
55 * SECTION: Helper functions (REDUNDANT FROM user/ws/index.php - someone could refactor this...)
56 * 986: function formatVerId($verId)
57 * 996: function formatWorkspace($wsid)
58 * 1023: function formatCount($count)
59 * 1050: function versionsInOtherWS($table,$uid)
60 * 1080: function showStageChangeLog($table,$id,$stageCommands)
61 * 1129: function subElements($uid,$treeLevel,$origId=0)
62 * 1232: function subElements_getNonPageRecords($tN, $uid, &$recList)
63 * 1262: function subElements_renderItem(&$tCell,$tN,$uid,$rec,$origId,$iconMode,$HTMLdata)
64 * 1331: function markupNewOriginals()
65 * 1353: function createDiffView($table, $diff_1_record, $diff_2_record)
66 * 1470: function displayWorkspaceOverview_stageCmd($table,&$rec_off)
67 * 1557: function displayWorkspaceOverview_commandLinks($table,&$rec_on,&$rec_off,$vType)
68 * 1627: function displayWorkspaceOverview_commandLinksSub($table,$rec,$origId)
69 *
70 * SECTION: Processing
71 * 1683: function publishAction()
72 *
73 * TOTAL FUNCTIONS: 27
74 * (This index is automatically created/updated by the extension "extdeveval")
75 *
76 */
77
78
79 // DEFAULT initialization of a module [BEGIN]
80 unset($MCONF);
81 require ('conf.php');
82 require ($BACK_PATH.'init.php');
83 require ($BACK_PATH.'template.php');
84 $LANG->includeLLFile('EXT:version/locallang.xml');
85 require_once (PATH_t3lib.'class.t3lib_scbase.php');
86 // DEFAULT initialization of a module [END]
87
88 require_once(PATH_t3lib.'class.t3lib_diff.php');
89 require_once(PATH_typo3.'mod/user/ws/class.wslib.php');
90 require_once(PATH_t3lib.'class.t3lib_pagetree.php');
91 require_once(PATH_t3lib.'class.t3lib_tcemain.php');
92
93
94
95 /**
96 * Versioning module, including workspace management
97 *
98 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
99 * @package TYPO3
100 * @subpackage core
101 */
102 class tx_version_cm1 extends t3lib_SCbase {
103
104 // Default variables for backend modules
105 var $MCONF = array(); // Module configuration
106 var $MOD_MENU = array(); // Module menu items
107 var $MOD_SETTINGS = array(); // Module session settings
108
109 /**
110 * document template object
111 *
112 * @var mediumDoc
113 */
114 var $doc;
115 var $content; // Accumulated content
116
117
118 // Internal:
119 var $showWorkspaceCol = 0;
120 var $formatWorkspace_cache = array();
121 var $formatCount_cache = array();
122 var $targets = array(); // Accumulation of online targets.
123 var $pageModule = ''; // Name of page module
124 var $publishAccess = FALSE;
125 var $be_user_Array = array();
126 var $stageIndex = array();
127 var $recIndex = array();
128
129
130
131
132
133
134 /*********************************
135 *
136 * Standard module initialization
137 *
138 *********************************/
139
140 /**
141 * Initialize menu configuration
142 *
143 * @return void
144 */
145 function menuConfig() {
146
147 // Menu items:
148 $this->MOD_MENU = array(
149 'filter' => array(
150 1 => 'Drafts',
151 2 => 'Archive',
152 0 => 'All',
153 ),
154 'display' => array(
155 0 => '[Live workspace]',
156 -98 => 'Draft Workspaces',
157 -99 => 'All',
158 -1 => '[Default Draft]'
159 ),
160 'diff' => ''
161 );
162
163 // Add workspaces:
164 if ($GLOBALS['BE_USER']->workspace===0) { // Spend time on this only in online workspace because it might take time:
165 $workspaces = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,title,adminusers,members,reviewers','sys_workspace','pid=0'.t3lib_BEfunc::deleteClause('sys_workspace'),'','title');
166 foreach($workspaces as $rec) {
167 if ($GLOBALS['BE_USER']->checkWorkspace($rec)) {
168 $this->MOD_MENU['display'][$rec['uid']] = '['.$rec['uid'].'] '.$rec['title'];
169 }
170 }
171 }
172
173 // CLEANSE SETTINGS
174 $this->MOD_SETTINGS = t3lib_BEfunc::getModuleData($this->MOD_MENU, t3lib_div::_GP('SET'), $this->MCONF['name'], 'ses');
175 }
176
177 /**
178 * Main function of the module. Write the content to $this->content
179 *
180 * @return void
181 */
182 function main() {
183 global $BE_USER,$LANG,$BACK_PATH,$TCA_DESCR,$TCA,$CLIENT,$TYPO3_CONF_VARS;
184
185 // Setting module configuration:
186 $this->MCONF = $GLOBALS['MCONF'];
187
188 $this->REQUEST_URI = str_replace('&sendToReview=1','',t3lib_div::getIndpEnv('REQUEST_URI'));
189
190 // Draw the header.
191 $this->doc = t3lib_div::makeInstance('mediumDoc');
192 $this->doc->backPath = $BACK_PATH;
193 $this->doc->form='<form action="" method="post">';
194
195 // Add styles
196 $this->doc->inDocStylesArray[$GLOBALS['MCONF']['name']] = '
197 .version-diff-1 { background-color: green; }
198 .version-diff-2 { background-color: red; }
199 ';
200
201 // Setting up the context sensitive menu:
202 $CMparts = $this->doc->getContextMenuCode();
203 $this->doc->JScode.= $CMparts[0];
204 $this->doc->bodyTagAdditions = $CMparts[1];
205 $this->doc->postCode.= $CMparts[2];
206
207 // Getting input data:
208 $this->id = intval(t3lib_div::_GP('id')); // Page id. If set, indicates activation from Web>Versioning module
209 if (!$this->id) {
210 $this->uid = intval(t3lib_div::_GP('uid')); // Record uid. Goes with table name to indicate specific record
211 $this->table = t3lib_div::_GP('table'); // Record table. Goes with uid to indicate specific record
212 } else {
213 $this->uid = $this->id;
214 $this->table = 'pages';
215 }
216 $this->details = t3lib_div::_GP('details'); // Page id. If set, indicates activation from Web>Versioning module
217 $this->diffOnly = t3lib_div::_GP('diffOnly'); // Flag. If set, shows only the offline version and with diff-view
218
219 // Force this setting:
220 $this->MOD_SETTINGS['expandSubElements'] = TRUE;
221 $this->MOD_SETTINGS['diff'] = $this->details || $this->MOD_SETTINGS['diff']?1:0;
222
223 // Reading the record:
224 $record = t3lib_BEfunc::getRecord($this->table,$this->uid);
225 if ($record['pid']==-1) {
226 $record = t3lib_BEfunc::getRecord($this->table,$record['t3ver_oid']);
227 }
228 $pidValue = $this->table==='pages' ? $this->uid : $record['pid'];
229
230 // Checking access etc.
231 if (is_array($record) && $TCA[$this->table]['ctrl']['versioningWS']) {
232 $this->uid = $record['uid']; // Might have changed if new live record was found!
233
234 // Access check!
235 // The page will show only if there is a valid page and if this page may be viewed by the user
236 $this->pageinfo = t3lib_BEfunc::readPageAccess($pidValue,$this->perms_clause);
237 $access = is_array($this->pageinfo) ? 1 : 0;
238
239 if (($pidValue && $access) || ($BE_USER->user['admin'] && !$pidValue)) {
240
241 // JavaScript
242 $this->doc->JScode.= '
243 <script language="javascript" type="text/javascript">
244 script_ended = 0;
245 function jumpToUrl(URL) {
246 window.location.href = URL;
247 }
248
249 function hlSubelements(origId, verId, over, diffLayer) { //
250 if (over) {
251 document.getElementById(\'orig_\'+origId).attributes.getNamedItem("class").nodeValue = \'typo3-ver-hl\';
252 document.getElementById(\'ver_\'+verId).attributes.getNamedItem("class").nodeValue = \'typo3-ver-hl\';
253 if (diffLayer) {
254 document.getElementById(\'diff_\'+verId).style.visibility = \'visible\';
255 }
256 } else {
257 document.getElementById(\'orig_\'+origId).attributes.getNamedItem("class").nodeValue = \'typo3-ver\';
258 document.getElementById(\'ver_\'+verId).attributes.getNamedItem("class").nodeValue = \'typo3-ver\';
259 if (diffLayer) {
260 document.getElementById(\'diff_\'+verId).style.visibility = \'hidden\';
261 }
262 }
263 }
264 </script>
265 ';
266
267 // If another page module was specified, replace the default Page module with the new one
268 $newPageModule = trim($BE_USER->getTSConfigVal('options.overridePageModule'));
269 $this->pageModule = t3lib_BEfunc::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
270
271 // Setting publish access permission for workspace:
272 $this->publishAccess = $BE_USER->workspacePublishAccess($BE_USER->workspace);
273
274
275 $headerSection = $this->doc->getHeader('pages',$this->pageinfo,$this->pageinfo['_thePath']).'<br/>'.$LANG->sL('LLL:EXT:lang/locallang_core.php:labels.path').': '.t3lib_div::fixed_lgd_pre($this->pageinfo['_thePath'],50);
276
277 $this->content.=$this->doc->startPage($LANG->getLL('title'));
278 $this->content.=$this->doc->header($LANG->getLL('title'));
279 $this->content.=$this->doc->spacer(5);
280 $this->content.=$this->doc->section('',$headerSection);
281 $this->content.=$this->doc->divider(5);
282
283 // Render content:
284 if ($this->id) {
285 $this->workspaceMgm();
286 } else {
287 $this->versioningMgm();
288 }
289
290 // ShortCut
291 if ($BE_USER->mayMakeShortcut()) {
292 $this->content.=$this->doc->spacer(20).$this->doc->section('',$this->doc->makeShortcutIcon('id',implode(',',array_keys($this->MOD_MENU)),$this->MCONF['name']));
293 }
294 }
295
296 $this->content.=$this->doc->spacer(10);
297 } else {
298 // If no access or id value, create empty document:
299 $this->content.=$this->doc->startPage($LANG->getLL('title'));
300 $this->content.=$this->doc->section($LANG->getLL('clickAPage_header'),$LANG->getLL('clickAPage_content'),0,1);
301 }
302 }
303
304 /**
305 * Outputs accumulated module content to browser.
306 *
307 * @return void
308 */
309 function printContent() {
310
311 $this->content.=$this->doc->endPage();
312 echo $this->content;
313 }
314
315
316
317
318
319
320
321
322
323
324 /******************************
325 *
326 * Versioning management
327 *
328 ******************************/
329
330 /**
331 * Management of versions for record
332 *
333 * @return void
334 */
335 function versioningMgm() {
336 global $TCA;
337
338 // Diffing:
339 $diff_1 = t3lib_div::_POST('diff_1');
340 $diff_2 = t3lib_div::_POST('diff_2');
341 if (t3lib_div::_POST('do_diff')) {
342 $content='';
343 $content.='<h3>DIFFING:</h3>';
344 if ($diff_1 && $diff_2) {
345 $diff_1_record = t3lib_BEfunc::getRecord($this->table, $diff_1);
346 $diff_2_record = t3lib_BEfunc::getRecord($this->table, $diff_2);
347
348 if (is_array($diff_1_record) && is_array($diff_2_record)) {
349 t3lib_div::loadTCA($this->table);
350 $t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff');
351
352 $tRows=array();
353 $tRows[] = '
354 <tr class="bgColor5 tableheader">
355 <td>Fieldname:</td>
356 <td width="98%">Colored diff-view:</td>
357 </tr>
358 ';
359 foreach($diff_1_record as $fN => $fV) {
360 if ($TCA[$this->table]['columns'][$fN] && $TCA[$this->table]['columns'][$fN]['config']['type']!='passthrough' && !t3lib_div::inList('t3ver_label',$fN)) {
361 if (strcmp($diff_1_record[$fN],$diff_2_record[$fN])) {
362
363 $diffres = $t3lib_diff_Obj->makeDiffDisplay(
364 t3lib_BEfunc::getProcessedValue($this->table,$fN,$diff_2_record[$fN],0,1),
365 t3lib_BEfunc::getProcessedValue($this->table,$fN,$diff_1_record[$fN],0,1)
366 );
367
368 $tRows[] = '
369 <tr class="bgColor4">
370 <td>'.$fN.'</td>
371 <td width="98%">'.$diffres.'</td>
372 </tr>
373 ';
374 }
375 }
376 }
377
378 if (count($tRows)>1) {
379 $content.='<table border="0" cellpadding="1" cellspacing="1" width="100%">'.implode('',$tRows).'</table><br/><br/>';
380 } else {
381 $content.='Records matches completely on all editable fields!';
382 }
383 } else $content.='ERROR: Records could strangely not be found!';
384 } else {
385 $content.='ERROR: You didn\'t select two sources for diffing!';
386 }
387 }
388
389 // Element:
390 $record = t3lib_BEfunc::getRecord($this->table,$this->uid);
391 $recordIcon = t3lib_iconWorks::getIconImage($this->table,$record,$this->doc->backPath,'class="absmiddle"');
392 $recTitle = t3lib_BEfunc::getRecordTitle($this->table,$record,TRUE);
393
394 // Display versions:
395 $content.='
396 '.$recordIcon.$recTitle.'
397 <form name="theform" action="'.str_replace('&sendToReview=1','',$this->REQUEST_URI).'" method="post">
398 <table border="0" cellspacing="1" cellpadding="1">';
399 $content.='
400 <tr class="bgColor5 tableheader">
401 <td>&nbsp;</td>
402 <td>&nbsp;</td>
403 <td>Title</td>
404 <td>UID</td>
405 <td title="t3ver_oid - Reference to live version UID">oid</td>
406 <td title="t3ver_id - Version number, incremental integer">id</td>
407 <td title="t3ver_wsid - Workspace ID. There can be only one version of an element per ID (except ID zero).">wsid</td>
408 <td title="t3ver_state - Special states of a version: 1=Placeholder for &quot;New&quot;. 2=Marked deleted.">state</td>
409 <td title="t3ver_stage - Publishing stage: Editing (0), review (1), publish (10), rejected (-1).">stage</td>
410 <td title="t3ver_count - Life cycle counter. Incremented each time element is unpublished.">count</td>
411 <td>pid</td>
412 <td>t3ver_label</td>
413 <td colspan="2"><input type="submit" name="do_diff" value="Diff" /></td>
414 </tr>';
415
416 $versions = t3lib_BEfunc::selectVersionsOfRecord($this->table, $this->uid, '*', $GLOBALS['BE_USER']->workspace);
417 foreach($versions as $row) {
418 $adminLinks = $this->adminLinks($this->table,$row);
419
420 $content.='
421 <tr class="'.($row['uid']!=$this->uid ? 'bgColor4' : 'bgColor2 tableheader').'">
422 <td>'.($row['uid']!=$this->uid ? '<a href="'.$this->doc->issueCommand('&cmd['.$this->table.']['.$this->uid.'][version][swapWith]='.$row['uid'].'&cmd['.$this->table.']['.$this->uid.'][version][action]=swap').'">'.
423 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/insert1.gif','width="14" height="14"').' alt="" title="SWAP with current" />'.
424 '</a>' /* (
425 $this->table == 'pages' ?
426 '<a href="'.$this->doc->issueCommand('&cmd['.$this->table.']['.$this->uid.'][version][action]=swap&cmd['.$this->table.']['.$this->uid.'][version][swapWith]='.$row['uid'].'&cmd['.$this->table.']['.$this->uid.'][version][swapContent]=1').'">'.
427 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/insert2.gif','width="14" height="14"').' alt="" title="Publish page AND content!" />'.
428 '</a>'.
429 '<a href="'.$this->doc->issueCommand('&cmd['.$this->table.']['.$this->uid.'][version][action]=swap&cmd['.$this->table.']['.$this->uid.'][version][swapWith]='.$row['uid'].'&cmd['.$this->table.']['.$this->uid.'][version][swapContent]=ALL').'">'.
430 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/insert4.gif','width="14" height="14"').' alt="" title="Publish page AND content! - AND ALL SUBPAGES!" />'.
431 '</a>' : '') */ : '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/blinkarrow_left.gif','width="5" height="9"').' alt="" title="CURRENT ONLINE VERSION!"/>').'</td>
432 <td nowrap="nowrap">'.$adminLinks.'</td>
433 <td nowrap="nowrap">'.t3lib_BEfunc::getRecordTitle($this->table,$row,TRUE).'</td>
434 <td>'.$row['uid'].'</td>
435 <td>'.$row['t3ver_oid'].'</td>
436 <td>'.$row['t3ver_id'].'</td>
437 <td>'.$row['t3ver_wsid'].'</td>
438 <td>'.$row['t3ver_state'].'</td>
439 <td>'.$row['t3ver_stage'].'</td>
440 <td>'.$row['t3ver_count'].'</td>
441 <td>'.$row['pid'].'</td>
442 <td nowrap="nowrap"><a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick('&edit['.$this->table.']['.$row['uid'].']=edit&columnsOnly=t3ver_label',$this->doc->backPath)).'"><img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/edit2.gif','width="11" height="12"').' alt="" title="Edit"/></a>'.htmlspecialchars($row['t3ver_label']).'</td>
443 <td class="version-diff-1"><input type="radio" name="diff_1" value="'.$row['uid'].'"'.($diff_1==$row['uid'] ? ' checked="checked"':'').'/></td>
444 <td class="version-diff-2"><input type="radio" name="diff_2" value="'.$row['uid'].'"'.($diff_2==$row['uid'] ? ' checked="checked"':'').'/></td>
445 </tr>';
446
447 // Show sub-content if the table is pages AND it is not the online branch (because that will mostly render the WHOLE tree below - not smart;)
448 if ($this->table == 'pages' && $row['uid']!=$this->uid) {
449 $sub = $this->pageSubContent($row['uid']);
450
451 if ($sub) {
452 $content.='
453 <tr>
454 <td></td>
455 <td></td>
456 <td colspan="10">'.$sub.'</td>
457 <td colspan="2"></td>
458 </tr>';
459 }
460 }
461 }
462 $content.='</table></form>';
463
464 $this->content.=$this->doc->section('',$content,0,1);
465
466
467 // Create new:
468 $content='
469
470 <form action="'.$this->doc->backPath.'tce_db.php" method="post">
471 Label: <input type="text" name="cmd['.$this->table.']['.$this->uid.'][version][label]" /><br/>
472 '.($this->table == 'pages' ? '<select name="cmd['.$this->table.']['.$this->uid.'][version][treeLevels]">
473 '.($GLOBALS['BE_USER']->workspaceVersioningTypeAccess(0) ? '<option value="0">Page: Page + content</option>' : '').'
474 '.($GLOBALS['BE_USER']->workspaceVersioningTypeAccess(1) ? '<option value="100">Branch: All subpages</option>' : '').'
475 '.($GLOBALS['BE_USER']->workspaceVersioningTypeAccess(-1) ? '<option value="-1">Element: Just record</option>' : '').'
476 </select>' : '').'
477 <br/><input type="hidden" name="cmd['.$this->table.']['.$this->uid.'][version][action]" value="new" />
478 <input type="hidden" name="prErr" value="1" />
479 <input type="hidden" name="redirect" value="'.htmlspecialchars($this->REQUEST_URI).'" />
480 <input type="submit" name="_" value="Create new version" />
481
482 </form>
483
484 ';
485
486 $this->content.=$this->doc->spacer(15);
487 $this->content.=$this->doc->section('Create new version',$content,0,1);
488
489 }
490
491 /**
492 * Recursively look for children for page version with $pid
493 *
494 * @param integer UID of page record for which to look up sub-elements following that version
495 * @param integer Counter, do not set (limits to 100 levels)
496 * @return string Table with content if any
497 */
498 function pageSubContent($pid,$c=0) {
499 global $TCA;
500
501 $tableNames = t3lib_div::removeArrayEntryByValue(array_keys($TCA),'pages');
502 $tableNames[] = 'pages';
503
504 foreach($tableNames as $tN) {
505 // Basically list ALL tables - not only those being copied might be found!
506 #if ($TCA[$tN]['ctrl']['versioning_followPages'] || $tN=='pages') {
507 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $tN, 'pid='.intval($pid).t3lib_BEfunc::deleteClause($tN), '', ($TCA[$tN]['ctrl']['sortby'] ? $TCA[$tN]['ctrl']['sortby'] : ''));
508
509 if ($GLOBALS['TYPO3_DB']->sql_num_rows($mres)) {
510 $content.='
511 <tr>
512 <td colspan="4" class="'.($TCA[$tN]['ctrl']['versioning_followPages'] ? 'bgColor6' : ($tN=='pages' ? 'bgColor5' : 'bgColor-10')).'"'.(!$TCA[$tN]['ctrl']['versioning_followPages'] && $tN!='pages' ? ' style="color: #666666; font-style:italic;"':'').'>'.$tN.'</td>
513 </tr>';
514 while ($subrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
515 $ownVer = $this->lookForOwnVersions($tN,$subrow['uid']);
516 $content.='
517 <tr>
518 <td>'.$this->adminLinks($tN,$subrow).'</td>
519 <td>'.$subrow['uid'].'</td>
520 '.($ownVer>1 ? '<td style="font-weight: bold; background-color: yellow;"><a href="index.php?table='.rawurlencode($tN).'&uid='.$subrow['uid'].'">'.($ownVer-1).'</a></td>' : '<td></td>').'
521 <td width="98%">'.t3lib_BEfunc::getRecordTitle($tN,$subrow,TRUE).'</td>
522 </tr>';
523
524 if ($tN == 'pages' && $c<100) {
525 $sub = $this->pageSubContent($subrow['uid'],$c+1);
526
527 if ($sub) {
528 $content.='
529 <tr>
530 <td></td>
531 <td></td>
532 <td></td>
533 <td width="98%">'.$sub.'</td>
534 </tr>';
535 }
536 }
537 }
538 }
539 #}
540 }
541
542 return $content ? '<table border="1" cellpadding="1" cellspacing="0" width="100%">'.$content.'</table>' : '';
543 }
544
545 /**
546 * Look for number of versions of a record
547 *
548 * @param string Table name
549 * @param integer Record uid
550 * @return integer Number of versions for record, false if none.
551 */
552 function lookForOwnVersions($table,$uid) {
553 global $TCA;
554
555 $versions = t3lib_BEfunc::selectVersionsOfRecord($table, $uid, 'uid');
556 if (is_array($versions)) {
557 return count($versions);
558 }
559 return FALSE;
560 }
561
562 /**
563 * Administrative links for a table / record
564 *
565 * @param string Table name
566 * @param array Record for which administrative links are generated.
567 * @return string HTML link tags.
568 */
569 function adminLinks($table,$row) {
570 global $BE_USER;
571
572 // Edit link:
573 $adminLink = '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick('&edit['.$table.']['.$row['uid'].']=edit',$this->doc->backPath)).'">'.
574 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/edit2.gif','width="11" height="12"').' alt="" title="Edit"/>'.
575 '</a>';
576
577 // Delete link:
578 $adminLink.= '<a href="'.htmlspecialchars($this->doc->issueCommand('&cmd['.$table.']['.$row['uid'].'][delete]=1')).'">'.
579 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/garbage.gif','width="11" height="12"').' alt="" title="Delete"/>'.
580 '</a>';
581
582
583
584 if ($table == 'pages') {
585
586 // If another page module was specified, replace the default Page module with the new one
587 $newPageModule = trim($BE_USER->getTSConfigVal('options.overridePageModule'));
588 $pageModule = t3lib_BEfunc::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
589
590 // Perform some acccess checks:
591 $a_wl = $BE_USER->check('modules','web_list');
592 $a_wp = t3lib_extMgm::isLoaded('cms') && $BE_USER->check('modules',$pageModule);
593
594 $adminLink.='<a href="#" onclick="top.loadEditId('.$row['uid'].');top.goToModule(\''.$pageModule.'\'); return false;">'.
595 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,t3lib_extMgm::extRelPath('cms').'layout/layout.gif','width="14" height="12"').' title="" alt="" />'.
596 '</a>';
597 $adminLink.='<a href="#" onclick="top.loadEditId('.$row['uid'].');top.goToModule(\'web_list\'); return false;">'.
598 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'mod/web/list/list.gif','width="14" height="12"').' title="" alt="" />'.
599 '</a>';
600
601 // "View page" icon is added:
602 $adminLink.='<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($row['uid'],$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($row['uid']))).'">'.
603 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/zoom.gif','width="12" height="12"').' title="" alt="" />'.
604 '</a>';
605 } else {
606 if ($row['pid']==-1) {
607 $getVars = '&ADMCMD_vPrev['.rawurlencode($table.':'.$row['t3ver_oid']).']='.$row['uid'];
608
609 // "View page" icon is added:
610 $adminLink.='<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($row['_REAL_PID'],$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($row['_REAL_PID']),'','',$getVars)).'">'.
611 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/zoom.gif','width="12" height="12"').' title="" alt="" />'.
612 '</a>';
613 }
614 }
615
616 return $adminLink;
617 }
618
619
620
621
622
623
624
625
626
627
628
629 /******************************
630 *
631 * Workspace management
632 *
633 ******************************/
634
635 /**
636 * Management of workspace for page ID
637 * Called when $this->id is set.
638 *
639 * @return void
640 */
641 function workspaceMgm() {
642
643 $menu = '';
644 if ($GLOBALS['BE_USER']->workspace===0) {
645 $menu.= t3lib_BEfunc::getFuncMenu($this->id,'SET[filter]',$this->MOD_SETTINGS['filter'],$this->MOD_MENU['filter']);
646 $menu.= t3lib_BEfunc::getFuncMenu($this->id,'SET[display]',$this->MOD_SETTINGS['display'],$this->MOD_MENU['display']);
647 }
648 if (!$this->details && $GLOBALS['BE_USER']->workspace && !$this->diffOnly) {
649 $menu.= t3lib_BEfunc::getFuncCheck($this->id,'SET[diff]',$this->MOD_SETTINGS['diff'],'','','id="checkDiff"').' <label for="checkDiff">Show difference view</label>';
650 }
651
652 if ($menu) {
653 $this->content.=$this->doc->section('',$menu,0,1);
654 }
655
656 // Perform workspace publishing action if buttons are pressed:
657 $errors = $this->publishAction();
658
659 // Generate workspace overview:
660 $WSoverview = $this->displayWorkspaceOverview();
661
662 // Buttons for publish / swap:
663 $actionLinks = '<br/>';
664 if ($GLOBALS['BE_USER']->workspace!==0) {
665 if ($this->publishAccess) {
666 $actionLinks.= '<input type="submit" name="_publish" value="Publish page" onclick="return confirm(\'Are you sure you want to publish all content '.($GLOBALS['BE_USER']->workspaceRec['publish_access']&1 ? 'in &quot;Publish&quot; stage ':'').'from this page?\');"/>';
667 if ($GLOBALS['BE_USER']->workspaceSwapAccess()) {
668 $actionLinks.= '<input type="submit" name="_swap" value="Swap page" onclick="return confirm(\'Are you sure you want to publish (swap) all content '.($GLOBALS['BE_USER']->workspaceRec['publish_access']&1 ? 'in &quot;Publish&quot; stage ':'').'from this page?\');" />';
669 }
670 } else {
671 $actionLinks.= $this->doc->icons(1).'You are not permitted to publish from this workspace';
672 }
673 }
674 $actionLinks.= '<input type="submit" name="_" value="Refresh" />';
675 $actionLinks.= '<input type="submit" name="_previewLink" value="Preview Link" />';
676 $actionLinks.= $this->displayWorkspaceOverview_allStageCmd();
677
678 if ($actionLinks || count($errors)) {
679 $this->content.= $this->doc->section('',$actionLinks.(count($errors) ? '<h3>Errors:</h3><br/>'.implode('<br/>',$errors).'<hr/>' : ''),0,1);
680 }
681
682 if (t3lib_div::_POST('_previewLink')) {
683 $params = 'id='.$this->id.'&ADMCMD_previewWS='.$GLOBALS['BE_USER']->workspace;
684 $previewUrl = t3lib_div::getIndpEnv('TYPO3_SITE_URL').'index.php?ADMCMD_prev='.t3lib_BEfunc::compilePreviewKeyword($params, $GLOBALS['BE_USER']->user['uid']);
685
686 $this->content.= $this->doc->section('Preview Url:','You can preview this page from the workspace using this link for the next 48 hours (does not require backend login):<br/><br/><a target="_blank" href="'.htmlspecialchars($previewUrl).'">'.$previewUrl.'</a>',0,1);
687 }
688
689 // Output overview content:
690 $this->content.= $this->doc->spacer(15);
691 $this->content.= $this->doc->section($this->details ? 'Details for version' : 'Workspace management', $WSoverview,0,1);
692
693 }
694
695 /**
696 * Rendering the overview of versions in the current workspace
697 *
698 * @return string HTML (table)
699 * @see typo3/mod/user/ws/index.php for sister function!
700 */
701 function displayWorkspaceOverview() {
702
703 // Initialize variables:
704 $this->showWorkspaceCol = $GLOBALS['BE_USER']->workspace===0 && $this->MOD_SETTINGS['display']<=-98;
705
706 // Get usernames and groupnames
707 $be_group_Array = t3lib_BEfunc::getListGroupNames('title,uid');
708 $groupArray = array_keys($be_group_Array);
709 $this->be_user_Array = t3lib_BEfunc::getUserNames();
710 if (!$GLOBALS['BE_USER']->isAdmin()) $this->be_user_Array = t3lib_BEfunc::blindUserNames($this->be_user_Array,$groupArray,1);
711
712 // Initialize Workspace ID and filter-value:
713 if ($GLOBALS['BE_USER']->workspace===0) {
714 $wsid = $this->details ? -99 : $this->MOD_SETTINGS['display']; // Set wsid to the value from the menu (displaying content of other workspaces)
715 $filter = $this->details ? 0 : $this->MOD_SETTINGS['filter'];
716 } else {
717 $wsid = $GLOBALS['BE_USER']->workspace;
718 $filter = 0;
719 }
720
721 // Initialize workspace object and request all pending versions:
722 $wslibObj = t3lib_div::makeInstance('wslib');
723
724 // Selecting ALL versions belonging to the workspace:
725 $versions = $wslibObj->selectVersionsInWorkspace($wsid, $filter, -99, $this->uid); // $this->uid is the page id of LIVE record.
726
727 // Traverse versions and build page-display array:
728 $pArray = array();
729 foreach($versions as $table => $records) {
730 foreach($records as $rec) {
731 $pageIdField = $table==='pages' ? 't3ver_oid' : 'realpid';
732 $this->displayWorkspaceOverview_setInPageArray(
733 $pArray,
734 $table,
735 $rec
736 );
737 }
738 }
739
740 // Make header of overview:
741 $tableRows = array();
742 if (count($pArray)) {
743 $tableRows[] = '
744 <tr class="bgColor5 tableheader">
745 '.($this->diffOnly?'':'<td nowrap="nowrap" colspan="2">Live Version:</td>').'
746 <td nowrap="nowrap" colspan="2">Workspace Versions:</td>
747 <td nowrap="nowrap"'.($this->diffOnly?' colspan="2"':' colspan="4"').'>Controls:</td>
748 </tr>';
749
750 // Add lines from overview:
751 $tableRows = array_merge($tableRows, $this->displayWorkspaceOverview_list($pArray));
752
753 $table = '<table border="0" cellpadding="0" cellspacing="1" class="lrPadding workspace-overview">'.implode('',$tableRows).'</table>';
754 } else $table = '';
755
756 $linkBack = t3lib_div::_GP('returnUrl') ? '<a href="'.htmlspecialchars(t3lib_div::_GP('returnUrl')).'" class="typo3-goBack"><img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/goback.gif','width="14" height="14"').' alt="" />Click here to go back</a><br/><br/>' : '';
757 $resetDiffOnly = $this->diffOnly ? '<a href="index.php?id='.intval($this->id).'" class="typo3-goBack">Show all information</a><br/><br/>' : '';
758
759 $versionSelector = $GLOBALS['BE_USER']->workspace ? $this->doc->getVersionSelector($this->id) : '';
760
761 return $versionSelector.$linkBack.$resetDiffOnly.$table.$this->markupNewOriginals();
762 }
763
764 /**
765 * Rendering the content for the publish / review overview:
766 * (Made for internal recursive calling)
767 *
768 * @param array Storage of the elements to display (see displayWorkspaceOverview() / displayWorkspaceOverview_setInPageArray())
769 * @return array Table rows, see displayWorkspaceOverview()
770 */
771 function displayWorkspaceOverview_list($pArray) {
772 global $TCA;
773
774 // If there ARE elements on this level, print them:
775 $warnAboutVersions_nonPages = FALSE;
776 $warnAboutVersions_page = FALSE;
777 if (is_array($pArray)) {
778 foreach($pArray as $table => $oidArray) {
779 foreach($oidArray as $oid => $recs) {
780
781 // Get CURRENT online record and icon based on "t3ver_oid":
782 $rec_on = t3lib_BEfunc::getRecord($table,$oid);
783 $icon = t3lib_iconWorks::getIconImage($table, $rec_on, $this->doc->backPath,' align="top" title="'.t3lib_BEfunc::getRecordIconAltText($rec_on,$table).'"');
784 if ($GLOBALS['BE_USER']->workspace===0) { // Only edit online records if in ONLINE workspace:
785 $icon = $this->doc->wrapClickMenuOnIcon($icon, $table, $rec_on['uid'], 1, '', '+edit,view,info,delete');
786 }
787
788 // Online version display:
789 // Create the main cells which will span over the number of versions there is.
790 $verLinkUrl = $TCA[$table]['ctrl']['versioningWS'];
791 $origElement = $icon.
792 ($verLinkUrl ? '<a href="'.htmlspecialchars('index.php?table='.$table.'&uid='.$rec_on['uid']).'">' : '').
793 t3lib_BEfunc::getRecordTitle($table,$rec_on,TRUE).
794 ($verLinkUrl ? '</a>' : '');
795 $mainCell_rowSpan = count($recs)>1 ? ' rowspan="'.count($recs).'"' : '';
796 $mainCell = '
797 <td align="center"'.$mainCell_rowSpan.'>'.$this->formatVerId($rec_on['t3ver_id']).'</td>
798 <td nowrap="nowrap"'.$mainCell_rowSpan.'>'.
799 $origElement.
800 '###SUB_ELEMENTS###'. // For substitution with sub-elements, if any.
801 '</td>';
802
803 // Offline versions display:
804 // Traverse the versions of the element
805 foreach($recs as $rec) {
806
807 // Get the offline version record and icon:
808 $rec_off = t3lib_BEfunc::getRecord($table,$rec['uid']);
809
810 // Prepare swap-mode values:
811 if ($table==='pages' && $rec_off['t3ver_swapmode']!=-1) {
812 if ($rec_off['t3ver_swapmode']>0) {
813 $vType = 'branch';
814 } else {
815 $vType = 'page';
816 }
817 } else {
818 $vType = 'element';
819 }
820
821 // Get icon
822 $icon = t3lib_iconWorks::getIconImage($table, $rec_off, $this->doc->backPath, ' align="top" title="'.t3lib_BEfunc::getRecordIconAltText($rec_off,$table).'"');
823 $tempUid = ($table != 'pages' || $vType==='branch' || $GLOBALS['BE_USER']->workspace===0 ? $rec_off['uid'] : $rec_on['uid']);
824 $icon = $this->doc->wrapClickMenuOnIcon($icon, $table, $tempUid, 1, '', '+edit,' . ($table == 'pages' ? 'view,info,' : '') . 'delete');
825
826 // Prepare diff-code:
827 if ($this->MOD_SETTINGS['diff'] || $this->diffOnly) {
828 $diffCode = '';
829 list($diffHTML,$diffPct) = $this->createDiffView($table, $rec_off, $rec_on);
830 if ($rec_on['t3ver_state']==1) { // New record:
831 $diffCode.= $this->doc->icons(1).'New element<br/>'; // TODO Localize?
832 $diffCode.= $diffHTML;
833 } elseif ($rec_off['t3ver_state']==2) {
834 $diffCode.= $this->doc->icons(2).'Deleted element<br/>';
835 } elseif ($rec_on['t3ver_state']==3) {
836 $diffCode.= $this->doc->icons(1).'Move-to placeholder (destination)<br/>';
837 } elseif ($rec_off['t3ver_state']==4) {
838 $diffCode.= $this->doc->icons(1).'Move-to pointer (source)<br/>';
839 } else {
840 $diffCode.= ($diffPct<0 ? 'N/A' : ($diffPct ? $diffPct.'% change:' : ''));
841 $diffCode.= $diffHTML;
842 }
843 } else $diffCode = '';
844
845 switch($vType) {
846 case 'element':
847 $swapLabel = ' [Element]';
848 $swapClass = 'ver-element';
849 $warnAboutVersions_nonPages = $warnAboutVersions_page; // Setting this if sub elements are found with a page+content (must be rendered prior to this of course!)
850 break;
851 case 'page':
852 $swapLabel = ' [Page]';
853 $swapClass = 'ver-page';
854 $warnAboutVersions_page = !$this->showWorkspaceCol; // This value is true only if multiple workspaces are shown and we need the opposite here.
855 break;
856 case 'branch':
857 $swapLabel = ' [Branch]';
858 $swapClass = 'ver-branch';
859 break;
860 }
861
862 // Modify main cell based on first version shown:
863 $subElements = array();
864 if ($table==='pages' && $rec_off['t3ver_swapmode']!=-1 && $mainCell) { // For "Page" and "Branch" swap modes where $mainCell is still carrying content (only first version)
865 $subElements['on'] = $this->subElements($rec_on['uid'], $rec_off['t3ver_swapmode']);
866 $subElements['off'] = $this->subElements($rec_off['uid'],$rec_off['t3ver_swapmode'],$rec_on['uid']);
867 }
868 $mainCell = str_replace('###SUB_ELEMENTS###', $subElements['on'], $mainCell);
869
870 // Create version element:
871 $versionsInOtherWS = $this->versionsInOtherWS($table, $rec_on['uid']);
872 $versionsInOtherWSWarning = $versionsInOtherWS && $GLOBALS['BE_USER']->workspace!==0 ? '<br/>'.$this->doc->icons(2).'Other version(s) in workspace '.$versionsInOtherWS : '';
873 $multipleWarning = (!$mainCell && $GLOBALS['BE_USER']->workspace!==0? '<br/>'.$this->doc->icons(3).'<b>Multiple versions in same workspace!</b>' : '');
874 $verWarning = $warnAboutVersions || ($warnAboutVersions_nonPages && $GLOBALS['TCA'][$table]['ctrl']['versioning_followPages'])? '<br/>'.$this->doc->icons(3).'<b>Version inside version!</b>' : '';
875 $verElement = $icon.
876 (!$this->details ? '<a href="'.htmlspecialchars($this->doc->backPath.t3lib_extMgm::extRelPath('version').'cm1/index.php?id='.($table==='pages'?$rec_on['uid']:$rec_on['pid']).'&details='.rawurlencode($table.':'.$rec_off['uid']).'&returnUrl='.rawurlencode($this->REQUEST_URI)).'">' : '').
877 t3lib_BEfunc::getRecordTitle($table,$rec_off,TRUE).
878 (!$this->details ? '</a>' : '').
879 $versionsInOtherWSWarning.
880 $multipleWarning.
881 $verWarning;
882
883 $ctrlTable = '
884 <td nowrap="nowrap">'.$this->showStageChangeLog($table,$rec_off['uid'],$this->displayWorkspaceOverview_stageCmd($table,$rec_off)).'</td>
885 <td nowrap="nowrap" class="'.$swapClass.'">'.
886 $this->displayWorkspaceOverview_commandLinks($table,$rec_on,$rec_off,$vType).
887 htmlspecialchars($swapLabel).
888 '&nbsp;&nbsp;</td>
889 '.(!$this->diffOnly?'<td nowrap="nowrap"><b>Lifecycle:</b> '.htmlspecialchars($this->formatCount($rec_off['t3ver_count'])).'</td>'. // Lifecycle
890 ($this->showWorkspaceCol ? '
891 <td nowrap="nowrap">&nbsp;&nbsp;<b>Workspace:</b> '.htmlspecialchars($this->formatWorkspace($rec_off['t3ver_wsid'])).'</td>' : ''):'');
892
893 if ($diffCode) {
894 $verElement = $verElement.'
895 <br/><b>Difference to live element:</b>
896 <table border="0" cellpadding="0" cellspacing="0" class="ver-verElement">
897 <tr>
898 <td class="c-diffCell">'.$diffCode.'</td>
899 </tr>
900 </table>';
901 }
902
903
904 // Create version cell:
905 $verCell = '
906 <td align="center">'.$this->formatVerId($rec_off['t3ver_id']).'</td>
907 <td nowrap="nowrap">'.
908 $verElement.
909 $subElements['off'].
910 '</td>
911 ';
912
913 // Compile table row:
914 $tableRows[] = '
915 <tr class="bgColor4">
916 '.
917 ($this->diffOnly?'':$mainCell).
918 $verCell.
919 $ctrlTable.
920 '
921 </tr>';
922
923 // Reset the main cell:
924 $mainCell = '';
925
926 }
927 }
928 }
929 }
930
931 return $tableRows;
932 }
933
934 /**
935 * Building up of the $pArray
936 * (Internal)
937 *
938 * @param array Array that is built up with the page tree structure
939 * @param string Table name
940 * @param array Table row
941 * @return void $pArray is passed by reference and modified internally
942 */
943 function displayWorkspaceOverview_setInPageArray(&$pArray,$table,$row) {
944 if (!$this->details || $this->details==$table.':'.$row['uid']) {
945 $pArray[$table][$row['t3ver_oid']][] = $row;
946 }
947 }
948
949 /**
950 * Links to stage change of a version
951 *
952 * @param string Table name
953 * @param array Offline record (version)
954 * @return string HTML content, mainly link tags and images.
955 */
956 function displayWorkspaceOverview_allStageCmd() {
957
958 $table = t3lib_div::_GP('table');
959 if ($table && $table!='pages') {
960 $uid = t3lib_div::_GP('uid');
961 if ($rec_off = t3lib_BEfunc::getRecordWSOL($table,$uid)) {
962 $uid = $rec_off['_ORIG_uid'];
963 }
964 } else $table = '';
965
966 if ($table) {
967 if ($uid && $this->recIndex[$table][$uid]) {
968 $sId = $this->recIndex[$table][$uid];
969 switch($sId) {
970 case 1:
971 $label = 'Comment for Reviewer:';
972 break;
973 case 10:
974 $label = 'Comment for Publisher:';
975 break;
976 }
977 } else $sId = 0;
978 } else {
979 if (count($this->stageIndex[1])) { // Review:
980 $sId = 1;
981 $color = '#666666';
982 $label = 'Sending %s item(s) to review. Comment for Reviewer:';
983 $titleAttrib = 'Send all to Review';
984 } elseif(count($this->stageIndex[10])) { // Publish:
985 $sId = 10;
986 $color = '#6666cc';
987 $label = 'Approving %s item(s) to publishing. Comment for Publisher:';
988 $titleAttrib = 'Approve all for Publishing';
989 } else {
990 $sId = 0;
991 }
992 }
993
994 if ($sId>0) {
995 $issueCmd = '';
996 $itemCount = 0;
997
998 if ($table && $uid && $this->recIndex[$table][$uid]) {
999 $issueCmd.='&cmd['.$table.']['.$uid.'][version][action]=setStage';
1000 $issueCmd.='&cmd['.$table.']['.$uid.'][version][stageId]='.$this->recIndex[$table][$uid];
1001 } else {
1002 foreach($this->stageIndex[$sId] as $table => $uidArray) {
1003 $issueCmd.='&cmd['.$table.']['.implode(',',$uidArray).'][version][action]=setStage';
1004 $issueCmd.='&cmd['.$table.']['.implode(',',$uidArray).'][version][stageId]='.$sId;
1005 $itemCount+=count($uidArray);
1006 }
1007 }
1008
1009 $onClick = 'var commentTxt=window.prompt("'.sprintf($label,$itemCount).'","");
1010 if (commentTxt!=null) {window.location.href="'.$this->doc->issueCommand($issueCmd,$this->REQUEST_URI).'&generalComment="+escape(commentTxt);}';
1011
1012 if (t3lib_div::_GP('sendToReview')) {
1013 $onClick.= ' else {window.location.href = "'.$this->REQUEST_URI.'"}';
1014 $actionLinks.=
1015 $this->doc->wrapScriptTags($onClick);
1016 } else {
1017 $onClick.= ' return false;';
1018 $actionLinks.=
1019 '<input type="submit" name="_" value="'.htmlspecialchars($titleAttrib).'" onclick="'.htmlspecialchars($onClick).'" />';
1020 }
1021 } elseif (t3lib_div::_GP('sendToReview')) {
1022 $onClick = 'window.location.href = "'.$this->REQUEST_URI.'";';
1023 $actionLinks.=
1024 $this->doc->wrapScriptTags($onClick);
1025 } else $actionLinks = '';
1026
1027 return $actionLinks;
1028 }
1029
1030
1031
1032
1033
1034
1035 /**************************************
1036 *
1037 * Helper functions (REDUNDANT FROM user/ws/index.php - someone could refactor this...)
1038 *
1039 *************************************/
1040
1041 /**
1042 * Formatting the version number for HTML output
1043 *
1044 * @param integer Version number
1045 * @return string Version number for output
1046 */
1047 function formatVerId($verId) {
1048 return '1.'.$verId;
1049 }
1050
1051 /**
1052 * Formatting workspace ID into a visual label
1053 *
1054 * @param integer Workspace ID
1055 * @return string Workspace title
1056 */
1057 function formatWorkspace($wsid) {
1058
1059 // Render, if not cached:
1060 if (!isset($this->formatWorkspace_cache[$wsid])) {
1061 switch($wsid) {
1062 case -1:
1063 $this->formatWorkspace_cache[$wsid] = '[Offline]';
1064 break;
1065 case 0:
1066 $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...
1067 break;
1068 default:
1069 list($titleRec) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('title','sys_workspace','uid='.intval($wsid).t3lib_BEfunc::deleteClause('sys_workspace'));
1070 $this->formatWorkspace_cache[$wsid] = '['.$wsid.'] '.$titleRec['title'];
1071 break;
1072 }
1073 }
1074
1075 return $this->formatWorkspace_cache[$wsid];
1076 }
1077
1078 /**
1079 * Format publishing count for version (lifecycle state)
1080 *
1081 * @param integer t3ver_count value (number of times it has been online)
1082 * @return string String translation of count.
1083 */
1084 function formatCount($count) {
1085
1086 // Render, if not cached:
1087 if (!isset($this->formatCount_cache[$count])) {
1088 switch($count) {
1089 case 0:
1090 $this->formatCount_cache[$count] = 'Draft';
1091 break;
1092 case 1:
1093 $this->formatCount_cache[$count] = 'Archive';
1094 break;
1095 default:
1096 $this->formatCount_cache[$count] = 'Published '.$count.' times';
1097 break;
1098 }
1099 }
1100
1101 return $this->formatCount_cache[$count];
1102 }
1103
1104 /**
1105 * Looking for versions of a record in other workspaces than the current
1106 *
1107 * @param string Table name
1108 * @param integer Record uid
1109 * @return string List of other workspace IDs
1110 */
1111 function versionsInOtherWS($table,$uid) {
1112
1113 // Check for duplicates:
1114 // Select all versions of record NOT in this workspace:
1115 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
1116 't3ver_wsid',
1117 $table,
1118 'pid=-1
1119 AND t3ver_oid='.intval($uid).'
1120 AND t3ver_wsid!='.intval($GLOBALS['BE_USER']->workspace).'
1121 AND (t3ver_wsid=-1 OR t3ver_wsid>0)'.
1122 t3lib_BEfunc::deleteClause($table),
1123 '',
1124 't3ver_wsid',
1125 '',
1126 't3ver_wsid'
1127 );
1128 if (count($rows)) {
1129 return implode(',',array_keys($rows));
1130 }
1131 }
1132
1133 /**
1134 * Looks up stage changes for version and displays a formatted view on mouseover.
1135 *
1136 * @param string Table name
1137 * @param integer Record ID
1138 * @param string HTML string to wrap the mouseover around (should be stage change links)
1139 * @return string HTML code.
1140 */
1141 function showStageChangeLog($table,$id,$stageCommands) {
1142 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
1143 'log_data,tstamp,userid',
1144 'sys_log',
1145 'action=6 and details_nr=30
1146 AND tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table,'sys_log').'
1147 AND recuid='.intval($id)
1148 );
1149
1150 $entry = array();
1151 foreach($rows as $dat) {
1152 $data = unserialize($dat['log_data']);
1153 $username = $this->be_user_Array[$dat['userid']] ? $this->be_user_Array[$dat['userid']]['username'] : '['.$dat['userid'].']';
1154
1155 switch($data['stage']) {
1156 case 1:
1157 $text = 'sent element to "Review"';
1158 break;
1159 case 10:
1160 $text = 'approved for "Publish"';
1161 break;
1162 case -1:
1163 $text = 'rejected element!';
1164 break;
1165 case 0:
1166 $text = 'reset to "Editing"';
1167 break;
1168 default:
1169 $text = '[undefined]';
1170 break;
1171 }
1172 $text = t3lib_BEfunc::dateTime($dat['tstamp']).': "'.$username.'" '.$text;
1173 $text.= ($data['comment']?'<br/>User Comment: <em>'.htmlspecialchars($data['comment']).'</em>':'');
1174
1175 $entry[] = $text;
1176 }
1177
1178 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>'.
1179 '<div class="logLayer" style="visibility: hidden; position: absolute;" id="log_'.$table.$id.'">'.implode('<hr/>',array_reverse($entry)).'</div>' : $stageCommands;
1180 }
1181
1182 /**
1183 * Creates display of sub elements of a page when the swap mode is either "Page" or "Branch" (0 / ALL)
1184 *
1185 * @param integer Page uid (for either online or offline version, but it MUST have swapmode/treeLevel set to >0 (not -1 indicating element versioning)
1186 * @param integer The treeLevel value, >0 indicates "branch" while 0 means page+content. (-1 would have meant element versioning, but that should never happen for a call to this function!)
1187 * @param integer For offline versions; This is t3ver_oid, the original ID of the online page.
1188 * @return string HTML content.
1189 */
1190 function subElements($uid,$treeLevel,$origId=0) {
1191 global $TCA;
1192
1193 if (!$this->details && ($GLOBALS['BE_USER']->workspace===0 || !$this->MOD_SETTINGS['expandSubElements'])) { // In online workspace we have a reduced view because otherwise it will bloat the listing:
1194 return '<br/>
1195 <img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/ol/joinbottom.gif','width="18" height="16"').' align="top" alt="" title="" />'.
1196 ($origId ?
1197 '<a href="'.htmlspecialchars($this->doc->backPath.t3lib_extMgm::extRelPath('version').'cm1/index.php?id='.$uid.'&details='.rawurlencode('pages:'.$uid).'&returnUrl='.rawurlencode($this->REQUEST_URI)).'">'.
1198 '<span class="typo3-dimmed"><em>[Sub elements, click for details]</em><span></a>' :
1199 '<span class="typo3-dimmed"><em>[Sub elements]</em><span>');
1200 } else { // For an offline workspace, show sub elements:
1201
1202 $tCell = array();
1203
1204 // Find records that follow pages when swapping versions:
1205 $recList = array();
1206 foreach($TCA as $tN => $tCfg) {
1207 if ($tN!='pages' && ($treeLevel>0 || $TCA[$tN]['ctrl']['versioning_followPages'])) {
1208 $this->subElements_getNonPageRecords($tN, $uid, $recList);
1209 }
1210 }
1211
1212 // Render records collected above:
1213 $elCount = count($recList)-1;
1214 foreach($recList as $c => $comb) {
1215 list($tN,$rec) = $comb;
1216
1217 $this->subElements_renderItem(
1218 $tCell,
1219 $tN,
1220 $uid,
1221 $rec,
1222 $origId,
1223 $c==$elCount && $treeLevel==0 ? 1 : 0, // If true, will show bottom-join icon.
1224 ''
1225 );
1226 }
1227
1228 // For branch, dive into the subtree:
1229 if ($treeLevel>0) {
1230
1231 // Drawing tree:
1232 $tree = t3lib_div::makeInstance('t3lib_pageTree');
1233 $tree->init('AND '.$GLOBALS['BE_USER']->getPagePermsClause(1));
1234 $tree->makeHTML = 2; // 2=Also rendering depth-data into the result array
1235 $tree->getTree($uid, 99, '');
1236
1237 // Traverse page tree:
1238 foreach($tree->tree as $data) {
1239
1240 // Render page in table cell:
1241 $this->subElements_renderItem(
1242 $tCell,
1243 'pages',
1244 $uid,
1245 t3lib_BEfunc::getRecord('pages',$data['row']['uid']), // Needs all fields, at least more than what is given in $data['row']...
1246 $origId,
1247 2, // 2=the join icon and icon for the record is not rendered for pages (where all is in $data['HTML']
1248 $data['HTML']
1249 );
1250
1251 // Find all records from page and collect in $recList:
1252 $recList = array();
1253 foreach($TCA as $tN => $tCfg) {
1254 if ($tN!=='pages') {
1255 $this->subElements_getNonPageRecords($tN, $data['row']['uid'], $recList);
1256 }
1257 }
1258
1259 // Render records collected above:
1260 $elCount = count($recList)-1;
1261 foreach($recList as $c => $comb) {
1262 list($tN,$rec) = $comb;
1263
1264 $this->subElements_renderItem(
1265 $tCell,
1266 $tN,
1267 $uid,
1268 $rec,
1269 $origId,
1270 $c==$elCount?1:0, // If true, will show bottom-join icon.
1271 $data['HTML_depthData']
1272 );
1273 }
1274 }
1275 }
1276
1277 return '
1278 <!-- Sub-element tree for versions -->
1279 <table border="0" cellpadding="0" cellspacing="1" class="ver-subtree">
1280 '.implode('',$tCell).'
1281 </table>';
1282 }
1283 }
1284
1285 /**
1286 * Select records from a table and add them to recList
1287 *
1288 * @param string Table name (from TCA)
1289 * @param integer PID to select records from
1290 * @param array Array where records are accumulated, passed by reference
1291 * @return void
1292 */
1293 function subElements_getNonPageRecords($tN, $uid, &$recList) {
1294 global $TCA;
1295
1296 $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
1297 '*',
1298 $tN,
1299 'pid='.intval($uid).
1300 ($TCA[$tN]['ctrl']['versioningWS'] ? ' AND t3ver_state=0' : '').
1301 t3lib_BEfunc::deleteClause($tN),
1302 '',
1303 $TCA[$tN]['ctrl']['sortby'] ? $TCA[$tN]['ctrl']['sortby'] : $GLOBALS['TYPO3_DB']->stripOrderBy($TCA[$tN]['ctrl']['default_sortby'])
1304 );
1305
1306 foreach($records as $rec) {
1307 $recList[] = array($tN,$rec);
1308 }
1309 }
1310
1311 /**
1312 * Render a single item in a subelement list into a table row:
1313 *
1314 * @param array Table rows, passed by reference
1315 * @param string Table name
1316 * @param integer Page uid for which the subelements are selected/shown
1317 * @param array Row of element in list
1318 * @param integer The uid of the online version of $uid. If zero it means we are drawing a row for the online version itself while a value means we are drawing display for an offline version.
1319 * @param integer Mode of icon display: 0=not the last, 1= is the last in list (make joinbottom icon then), 2=do not shown icons are all (for pages from the page tree already rendered)
1320 * @param string Prefix HTML data (icons for tree rendering)
1321 * @return void (Content accumulated in $tCell!)
1322 */
1323 function subElements_renderItem(&$tCell,$tN,$uid,$rec,$origId,$iconMode,$HTMLdata) {
1324 global $TCA;
1325
1326 // Initialize:
1327 $origUidFields = $TCA[$tN]['ctrl']['origUid'];
1328 $diffCode = '';
1329
1330 if ($origUidFields) { // If there is a field for this table with original uids we will use that to connect records:
1331 if (!$origId) { // In case we are displaying the online originals:
1332 $this->targets['orig_'.$uid.'_'.$tN.'_'.$rec['uid']] = $rec; // Build up target array (important that
1333 $tdParams = ' id="orig_'.$uid.'_'.$tN.'_'.$rec['uid'].'" class="typo3-ver"'; // Setting ID of the table row
1334 } else { // Version branch:
1335 if ($this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]]) { // If there IS a corresponding original record...:
1336
1337 // Prepare Table row parameters:
1338 $tdParams = ' onmouseover="hlSubelements(\''.$origId.'_'.$tN.'_'.$rec[$origUidFields].'\', \''.$uid.'_'.$tN.'_'.$rec[$origUidFields].'\', 1, '.($this->MOD_SETTINGS['diff']==2?1:0).');"'.
1339 ' onmouseout="hlSubelements(\''.$origId.'_'.$tN.'_'.$rec[$origUidFields].'\', \''.$uid.'_'.$tN.'_'.$rec[$origUidFields].'\', 0, '.($this->MOD_SETTINGS['diff']==2?1:0).');"'.
1340 ' id="ver_'.$uid.'_'.$tN.'_'.$rec[$origUidFields].'" class="typo3-ver"';
1341
1342 // Create diff view:
1343 if ($this->MOD_SETTINGS['diff']) {
1344 list($diffHTML,$diffPct) = $this->createDiffView($tN, $rec, $this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]]);
1345
1346 if ($this->MOD_SETTINGS['diff']==2) {
1347 $diffCode =
1348 ($diffPct ? '<span class="nobr">'.$diffPct.'% change</span>' : '-').
1349 '<div style="visibility: hidden; position: absolute;" id="diff_'.$uid.'_'.$tN.'_'.$rec[$origUidFields].'" class="diffLayer">'.
1350 $diffHTML.
1351 '</div>';
1352 } else {
1353 $diffCode =
1354 ($diffPct<0 ? 'N/A' : ($diffPct ? $diffPct.'% change:' : '')).
1355 $diffHTML;
1356 }
1357 }
1358
1359 // Unsetting the target fields allows us to mark all originals without a version in the subtree (see ->markupNewOriginals())
1360 unset($this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]]);
1361 } else { // No original record, so must be new:
1362 $tdParams = ' class="typo3-ver-new"';
1363 }
1364 }
1365 } else { // If no original uid column is supported for this table we are forced NOT to display any diff or highlighting.
1366 $tdParams = ' class="typo3-ver-noComp"';
1367 }
1368
1369 // Compile the cell:
1370 $tCell[] = '
1371 <tr'.$tdParams.'>
1372 <td class="iconTitle">'.
1373 $HTMLdata.
1374 ($iconMode < 2 ?
1375 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/ol/join'.($iconMode ? 'bottom' : '').'.gif','width="18" height="16"').' alt="" />'.
1376 t3lib_iconWorks::getIconImage($tN, $rec, $this->doc->backPath,'') : '').
1377 t3lib_BEfunc::getRecordTitle($tN, $rec, TRUE).
1378 '</td>
1379 <td class="cmdCell">'.
1380 $this->displayWorkspaceOverview_commandLinksSub($tN,$rec,$origId).
1381 '</td>'.($origId ? '<td class="diffCell">'.
1382 $diffCode.
1383 '</td>':'').'
1384 </tr>';
1385 }
1386
1387 /**
1388 * JavaScript code to mark up new records that are online (in sub element lists)
1389 *
1390 * @return string HTML javascript section
1391 */
1392 function markupNewOriginals() {
1393
1394 if (count($this->targets)) {
1395 $scriptCode = '';
1396 foreach($this->targets as $key => $rec) {
1397 $scriptCode.='
1398 document.getElementById(\''.$key.'\').attributes.getNamedItem("class").nodeValue = \'typo3-ver-new\';
1399 ';
1400 }
1401
1402 return $this->doc->wrapScriptTags($scriptCode);
1403 }
1404 }
1405
1406 /**
1407 * Create visual difference view of two records. Using t3lib_diff library
1408 *
1409 * @param string Table name
1410 * @param array New version record (green)
1411 * @param array Old version record (red)
1412 * @return array Array with two keys (0/1) with HTML content / percentage integer (if -1, then it means N/A) indicating amount of change
1413 */
1414 function createDiffView($table, $diff_1_record, $diff_2_record) {
1415 global $TCA;
1416
1417 // Initialize:
1418 $pctChange = 'N/A';
1419
1420 // Check that records are arrays:
1421 if (is_array($diff_1_record) && is_array($diff_2_record)) {
1422
1423 // Load full table description and initialize diff-object:
1424 t3lib_div::loadTCA($table);
1425 $t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff');
1426
1427 // Add header row:
1428 $tRows = array();
1429 $tRows[] = '
1430 <tr class="bgColor5 tableheader">
1431 <td>Fieldname:</td>
1432 <td width="98%" nowrap="nowrap">Colored diff-view:</td>
1433 </tr>
1434 ';
1435
1436 // Initialize variables to pick up string lengths in:
1437 $allStrLen = 0;
1438 $diffStrLen = 0;
1439
1440 // Traversing the first record and process all fields which are editable:
1441 foreach($diff_1_record as $fN => $fV) {
1442 if ($TCA[$table]['columns'][$fN] && $TCA[$table]['columns'][$fN]['config']['type']!='passthrough' && !t3lib_div::inList('t3ver_label',$fN)) {
1443
1444 // Check if it is files:
1445 $isFiles = FALSE;
1446 if (strcmp(trim($diff_1_record[$fN]),trim($diff_2_record[$fN])) &&
1447 $TCA[$table]['columns'][$fN]['config']['type']=='group' &&
1448 $TCA[$table]['columns'][$fN]['config']['internal_type']=='file') {
1449
1450 // Initialize:
1451 $uploadFolder = $TCA[$table]['columns'][$fN]['config']['uploadfolder'];
1452 $files1 = array_flip(t3lib_div::trimExplode(',', $diff_1_record[$fN],1));
1453 $files2 = array_flip(t3lib_div::trimExplode(',', $diff_2_record[$fN],1));
1454
1455 // Traverse filenames and read their md5 sum:
1456 foreach($files1 as $filename => $tmp) {
1457 $files1[$filename] = @is_file(PATH_site.$uploadFolder.'/'.$filename) ? md5(t3lib_div::getUrl(PATH_site.$uploadFolder.'/'.$filename)) : $filename;
1458 }
1459 foreach($files2 as $filename => $tmp) {
1460 $files2[$filename] = @is_file(PATH_site.$uploadFolder.'/'.$filename) ? md5(t3lib_div::getUrl(PATH_site.$uploadFolder.'/'.$filename)) : $filename;
1461 }
1462
1463 // Implode MD5 sums and set flag:
1464 $diff_1_record[$fN] = implode(' ',$files1);
1465 $diff_2_record[$fN] = implode(' ',$files2);
1466 $isFiles = TRUE;
1467 }
1468
1469 // If there is a change of value:
1470 if (strcmp(trim($diff_1_record[$fN]),trim($diff_2_record[$fN]))) {
1471
1472
1473 // Get the best visual presentation of the value and present that:
1474 $val1 = t3lib_BEfunc::getProcessedValue($table,$fN,$diff_2_record[$fN],0,1);
1475 $val2 = t3lib_BEfunc::getProcessedValue($table,$fN,$diff_1_record[$fN],0,1);
1476
1477 // Make diff result and record string lenghts:
1478 $diffres = $t3lib_diff_Obj->makeDiffDisplay($val1,$val2,$isFiles?'div':'span');
1479 $diffStrLen+= $t3lib_diff_Obj->differenceLgd;
1480 $allStrLen+= strlen($val1.$val2);
1481
1482 // If the compared values were files, substituted MD5 hashes:
1483 if ($isFiles) {
1484 $allFiles = array_merge($files1,$files2);
1485 foreach($allFiles as $filename => $token) {
1486 if (strlen($token)==32 && strstr($diffres,$token)) {
1487 $filename =
1488 t3lib_BEfunc::thumbCode(array($fN=>$filename),$table,$fN,$this->doc->backPath).
1489 $filename;
1490 $diffres = str_replace($token,$filename,$diffres);
1491 }
1492 }
1493 }
1494
1495 // Add table row with result:
1496 $tRows[] = '
1497 <tr class="bgColor4">
1498 <td>'.htmlspecialchars($GLOBALS['LANG']->sL(t3lib_BEfunc::getItemLabel($table,$fN))).'</td>
1499 <td width="98%">'.$diffres.'</td>
1500 </tr>
1501 ';
1502 } else {
1503 // Add string lengths even if value matched - in this was the change percentage is not high if only a single field is changed:
1504 $allStrLen+=strlen($diff_1_record[$fN].$diff_2_record[$fN]);
1505 }
1506 }
1507 }
1508
1509 // Calculate final change percentage:
1510 $pctChange = $allStrLen ? ceil($diffStrLen*100/$allStrLen) : -1;
1511
1512 // Create visual representation of result:
1513 if (count($tRows)>1) {
1514 $content.= '<table border="0" cellpadding="1" cellspacing="1" class="diffTable">'.implode('',$tRows).'</table>';
1515 } else {
1516 $content.= '<span class="nobr">'.$this->doc->icons(1).'Complete match on editable fields.</span>';
1517 }
1518 } else $content.= $this->doc->icons(3).'ERROR: Records could strangely not be found!';
1519
1520 // Return value:
1521 return array($content,$pctChange);
1522 }
1523
1524 /**
1525 * Links to stage change of a version
1526 *
1527 * @param string Table name
1528 * @param array Offline record (version)
1529 * @return string HTML content, mainly link tags and images.
1530 */
1531 function displayWorkspaceOverview_stageCmd($table,&$rec_off) {
1532 #debug($rec_off['t3ver_stage']);
1533 switch((int)$rec_off['t3ver_stage']) {
1534 case 0:
1535 $sId = 1;
1536 $sLabel = 'Editing';
1537 $color = '#666666';
1538 $label = 'Comment for Reviewer:';
1539 $titleAttrib = 'Send to Review';
1540 break;
1541 case 1:
1542 $sId = 10;
1543 $sLabel = 'Review';
1544 $color = '#6666cc';
1545 $label = 'Comment for Publisher:';
1546 $titleAttrib = 'Approve for Publishing';
1547 break;
1548 case 10:
1549 $sLabel = 'Publish';
1550 $color = '#66cc66';
1551 break;
1552 case -1:
1553 $sLabel = $this->doc->icons(2).'Rejected';
1554 $sId = 0;
1555 $color = '#ff0000';
1556 $label = 'Comment:';
1557 $titleAttrib = 'Reset stage';
1558 break;
1559 default:
1560 $sLabel = 'Undefined';
1561 $sId = 0;
1562 $color = '';
1563 break;
1564 }
1565 #debug($sId);
1566
1567 $raiseOk = !$GLOBALS['BE_USER']->workspaceCannotEditOfflineVersion($table,$rec_off);
1568
1569 if ($raiseOk && $rec_off['t3ver_stage']!=-1) {
1570 $onClick = 'var commentTxt=window.prompt("Please explain why you reject:","");
1571 if (commentTxt!=null) {window.location.href="'.$this->doc->issueCommand(
1572 '&cmd['.$table.']['.$rec_off['uid'].'][version][action]=setStage'.
1573 '&cmd['.$table.']['.$rec_off['uid'].'][version][stageId]=-1'
1574 ).'&cmd['.$table.']['.$rec_off['uid'].'][version][comment]="+escape(commentTxt);}'.
1575 ' return false;';
1576 // Reject:
1577 $actionLinks.=
1578 '<a href="#" onclick="'.htmlspecialchars($onClick).'">'.
1579 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/down.gif','width="14" height="14"').' alt="" align="top" title="Reject" />'.
1580 '</a>';
1581 } else {
1582 // Reject:
1583 $actionLinks.=
1584 '<img src="'.$this->doc->backPath.'gfx/clear.gif" width="14" height="14" alt="" align="top" title="" />';
1585 }
1586
1587 $actionLinks.= '<span style="background-color: '.$color.'; color: white;">'.$sLabel.'</span>';
1588
1589 // Raise
1590 if ($raiseOk) {
1591 $onClick = 'var commentTxt=window.prompt("'.$label.'","");
1592 if (commentTxt!=null) {window.location.href="'.$this->doc->issueCommand(
1593 '&cmd['.$table.']['.$rec_off['uid'].'][version][action]=setStage'.
1594 '&cmd['.$table.']['.$rec_off['uid'].'][version][stageId]='.$sId
1595 ).'&cmd['.$table.']['.$rec_off['uid'].'][version][comment]="+escape(commentTxt);}'.
1596 ' return false;';
1597 if ($rec_off['t3ver_stage']!=10) {
1598 $actionLinks.=
1599 '<a href="#" onclick="'.htmlspecialchars($onClick).'">'.
1600 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/up.gif','width="14" height="14"').' alt="" align="top" title="'.htmlspecialchars($titleAttrib).'" />'.
1601 '</a>';
1602
1603 $this->stageIndex[$sId][$table][] = $rec_off['uid'];
1604 $this->recIndex[$table][$rec_off['uid']] = $sId;
1605 }
1606 }
1607 return $actionLinks;
1608 }
1609
1610 /**
1611 * Links to publishing etc of a version
1612 *
1613 * @param string Table name
1614 * @param array Online record
1615 * @param array Offline record (version)
1616 * @param string Swap type, "branch", "page" or "element"
1617 * @return string HTML content, mainly link tags and images.
1618 */
1619 function displayWorkspaceOverview_commandLinks($table,&$rec_on,&$rec_off,$vType) {
1620 if ($this->publishAccess && (!($GLOBALS['BE_USER']->workspaceRec['publish_access']&1) || (int)$rec_off['t3ver_stage']===10)) {
1621 $actionLinks =
1622 '<a href="'.htmlspecialchars($this->doc->issueCommand(
1623 '&cmd['.$table.']['.$rec_on['uid'].'][version][action]=swap'.
1624 '&cmd['.$table.']['.$rec_on['uid'].'][version][swapWith]='.$rec_off['uid']
1625 )).'">'.
1626 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/insert1.gif','width="14" height="14"').' alt="" align="top" title="Publish" />'.
1627 '</a>';
1628 if ($GLOBALS['BE_USER']->workspaceSwapAccess()) {
1629 $actionLinks.=
1630 '<a href="'.htmlspecialchars($this->doc->issueCommand(
1631 '&cmd['.$table.']['.$rec_on['uid'].'][version][action]=swap'.
1632 '&cmd['.$table.']['.$rec_on['uid'].'][version][swapWith]='.$rec_off['uid'].
1633 '&cmd['.$table.']['.$rec_on['uid'].'][version][swapIntoWS]=1'
1634 )).'">'.
1635 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/swap.png','width="14" height="14"').' alt="" align="top" title="Swap" />'.
1636 '</a>';
1637 }
1638 }
1639
1640 if (!$GLOBALS['BE_USER']->workspaceCannotEditOfflineVersion($table,$rec_off)) {
1641 // Release
1642 $actionLinks.=
1643 '<a href="'.htmlspecialchars($this->doc->issueCommand('&cmd['.$table.']['.$rec_off['uid'].'][version][action]=clearWSID')).'" onclick="return confirm(\'Remove from workspace?\');">'.
1644 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/group_clear.gif','width="14" height="14"').' alt="" align="top" title="Remove from workspace" />'.
1645 '</a>';
1646
1647 // Edit
1648 if ($table==='pages' && $vType!=='element') {
1649 $tempUid = ($vType==='branch' || $GLOBALS['BE_USER']->workspace===0 ? $rec_off['uid'] : $rec_on['uid']);
1650 $actionLinks.=
1651 '<a href="#" onclick="top.loadEditId('.$tempUid.');top.goToModule(\''.$this->pageModule.'\'); return false;">'.
1652 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,t3lib_extMgm::extRelPath('cms').'layout/layout.gif','width="14" height="12"').' title="Edit page" alt="" />'.
1653 '</a>';
1654 } else {
1655 $params = '&edit['.$table.']['.$rec_off['uid'].']=edit';
1656 $actionLinks.=
1657 '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick($params,$this->doc->backPath)).'">'.
1658 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/edit2.gif','width="12" height="12"').' title="Edit element" alt="" />'.
1659 '</a>';
1660 }
1661 }
1662
1663 // History/Log
1664 $actionLinks.=
1665 '<a href="'.htmlspecialchars($this->doc->backPath.'show_rechis.php?element='.rawurlencode($table.':'.$rec_off['uid']).'&returnUrl='.rawurlencode($this->REQUEST_URI)).'">'.
1666 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/history2.gif','width="13" height="12"').' title="Show Log" alt="" />'.
1667 '</a>';
1668
1669 // View
1670 if ($table==='pages') {
1671 $tempUid = ($vType==='branch' || $GLOBALS['BE_USER']->workspace===0 ? $rec_off['uid'] : $rec_on['uid']);
1672 $actionLinks.=
1673 '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($tempUid,$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($tempUid))).'">'.
1674 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/zoom.gif','width="12" height="12"').' title="" alt="" />'.
1675 '</a>';
1676 }
1677
1678 return $actionLinks;
1679 }
1680
1681 /**
1682 * Links to publishing etc of a version
1683 *
1684 * @param string Table name
1685 * @param array Record
1686 * @param integer The uid of the online version of $uid. If zero it means we are drawing a row for the online version itself while a value means we are drawing display for an offline version.
1687 * @return string HTML content, mainly link tags and images.
1688 */
1689 function displayWorkspaceOverview_commandLinksSub($table,$rec,$origId) {
1690 $uid = $rec['uid'];
1691 if ($origId || $GLOBALS['BE_USER']->workspace===0) {
1692 if (!$GLOBALS['BE_USER']->workspaceCannotEditRecord($table,$rec)) {
1693 // Edit
1694 if ($table==='pages') {
1695 $actionLinks.=
1696 '<a href="#" onclick="top.loadEditId('.$uid.');top.goToModule(\''.$this->pageModule.'\'); return false;">'.
1697 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,t3lib_extMgm::extRelPath('cms').'layout/layout.gif','width="14" height="12"').' title="Edit page" alt="" />'.
1698 '</a>';
1699 } else {
1700 $params = '&edit['.$table.']['.$uid.']=edit';
1701 $actionLinks.=
1702 '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick($params,$this->doc->backPath)).'">'.
1703 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/edit2.gif','width="12" height="12"').' title="Edit element" alt="" />'.
1704 '</a>';
1705 }
1706 }
1707
1708 // History/Log
1709 $actionLinks.=
1710 '<a href="'.htmlspecialchars($this->doc->backPath.'show_rechis.php?element='.rawurlencode($table.':'.$uid).'&returnUrl='.rawurlencode($this->REQUEST_URI)).'">'.
1711 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/history2.gif','width="13" height="12"').' title="Show Log" alt="" />'.
1712 '</a>';
1713 }
1714
1715 // View
1716 if ($table==='pages') {
1717 $actionLinks.=
1718 '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($uid,$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($uid))).'">'.
1719 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/zoom.gif','width="12" height="12"').' title="" alt="" />'.
1720 '</a>';
1721 }
1722
1723 return $actionLinks;
1724 }
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734 /**********************************
1735 *
1736 * Processing
1737 *
1738 **********************************/
1739
1740 /**
1741 * Will publish workspace if buttons are pressed
1742 *
1743 * @return void
1744 */
1745 function publishAction() {
1746
1747 // If "Publish" or "Swap" buttons are pressed:
1748 if (t3lib_div::_POST('_publish') || t3lib_div::_POST('_swap')) {
1749
1750 if ($this->table==='pages') { // Making sure ->uid is a page ID!
1751 // Initialize workspace object and request all pending versions:
1752 $wslibObj = t3lib_div::makeInstance('wslib');
1753 $cmd = $wslibObj->getCmdArrayForPublishWS($GLOBALS['BE_USER']->workspace, t3lib_div::_POST('_swap'),$this->uid);
1754
1755 // Execute the commands:
1756 $tce = t3lib_div::makeInstance('t3lib_TCEmain');
1757 $tce->stripslashes_values = 0;
1758 $tce->start(array(), $cmd);
1759 $tce->process_cmdmap();
1760
1761 t3lib_BEfunc::getSetUpdateSignal('updatePageTree');
1762
1763 return $tce->errorLog;
1764 }
1765 }
1766 }
1767 }
1768
1769
1770
1771 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/version/cm1/index.php']) {
1772 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/version/cm1/index.php']);
1773 }
1774
1775
1776
1777
1778 // Make instance:
1779 $SOBE = t3lib_div::makeInstance('tx_version_cm1');
1780 $SOBE->init();
1781
1782
1783 $SOBE->main();
1784 $SOBE->printContent();
1785
1786 ?>