Bug #20852 » index_old.php

Administrator Admin, 2009-08-07 17:47

 
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
	var $doc;							// Document Template Object
109
	var $content;						// Accumulated content
110

    
111

    
112
		// Internal:
113
	var $showWorkspaceCol = 0;
114
	var $formatWorkspace_cache = array();
115
	var $formatCount_cache = array();
116
	var $targets = array();		// Accumulation of online targets.
117
	var $pageModule = '';			// Name of page module
118
	var $publishAccess = FALSE;
119
	var $be_user_Array = array();
120
	var $stageIndex = array();
121
	var $recIndex = array();
122

    
123

    
124

    
125

    
126

    
127

    
128
	/*********************************
129
	 *
130
	 * Standard module initialization
131
	 *
132
	 *********************************/
133

    
134
	/**
135
	 * Initialize menu configuration
136
	 *
137
	 * @return	void
138
	 */
139
	function menuConfig()	{
140

    
141
			// Menu items:
142
		$this->MOD_MENU = array(
143
			'filter' => array(
144
				1 => 'Drafts',
145
				2 => 'Archive',
146
				0 => 'All',
147
			),
148
			'display' => array(
149
				0 => '[Live workspace]',
150
				-98 => 'Draft Workspaces',
151
				-99 => 'All',
152
				-1 => '[Default Draft]'
153
			),
154
			'diff' => ''
155
		);
156

    
157
			// Add workspaces:
158
		if ($GLOBALS['BE_USER']->workspace===0)	{	// Spend time on this only in online workspace because it might take time:
159
			$workspaces = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,title,adminusers,members,reviewers','sys_workspace','pid=0'.t3lib_BEfunc::deleteClause('sys_workspace'),'','title');
160
			foreach($workspaces as $rec)	{
161
				if ($GLOBALS['BE_USER']->checkWorkspace($rec))	{
162
					$this->MOD_MENU['display'][$rec['uid']] = '['.$rec['uid'].'] '.$rec['title'];
163
				}
164
			}
165
		}
166

    
167
			// CLEANSE SETTINGS
168
		$this->MOD_SETTINGS = t3lib_BEfunc::getModuleData($this->MOD_MENU, t3lib_div::_GP('SET'), $this->MCONF['name'], 'ses');
169
	}
170

    
171
	/**
172
	 * Main function of the module. Write the content to $this->content
173
	 *
174
	 * @return	void
175
	 */
176
	function main()	{
177
		global $BE_USER,$LANG,$BACK_PATH,$TCA_DESCR,$TCA,$CLIENT,$TYPO3_CONF_VARS;
178

    
179
			// Setting module configuration:
180
		$this->MCONF = $GLOBALS['MCONF'];
181
		
182
		$this->REQUEST_URI = str_replace('&sendToReview=1','',t3lib_div::getIndpEnv('REQUEST_URI'));
183

    
184
			// Draw the header.
185
		$this->doc = t3lib_div::makeInstance('mediumDoc');
186
		$this->doc->backPath = $BACK_PATH;
187
		$this->doc->form='<form action="" method="post">';
188

    
189
	        // Add styles
190
		$this->doc->inDocStylesArray[$GLOBALS['MCONF']['name']] = '
191
.version-diff-1 { background-color: green; }
192
.version-diff-2 { background-color: red; }
193
';
194

    
195
			// Setting up the context sensitive menu:
196
		$CMparts = $this->doc->getContextMenuCode();
197
		$this->doc->JScode.= $CMparts[0];
198
		$this->doc->bodyTagAdditions = $CMparts[1];
199
		$this->doc->postCode.= $CMparts[2];
200

    
201
			// Getting input data:
202
		$this->id = intval(t3lib_div::_GP('id'));		// Page id. If set, indicates activation from Web>Versioning module
203
		if (!$this->id)	{
204
			$this->uid = intval(t3lib_div::_GP('uid'));		// Record uid. Goes with table name to indicate specific record
205
			$this->table = t3lib_div::_GP('table');			// Record table. Goes with uid to indicate specific record
206
		} else {
207
			$this->uid = $this->id;
208
			$this->table = 'pages';
209
		}
210
		$this->details = t3lib_div::_GP('details');		// Page id. If set, indicates activation from Web>Versioning module
211
		$this->diffOnly = t3lib_div::_GP('diffOnly');		// Flag. If set, shows only the offline version and with diff-view
212

    
213
			// Force this setting:
214
		$this->MOD_SETTINGS['expandSubElements'] = TRUE;
215
		$this->MOD_SETTINGS['diff'] = $this->details || $this->MOD_SETTINGS['diff']?1:0;
216

    
217
			// Reading the record:
218
		$record = t3lib_BEfunc::getRecord($this->table,$this->uid);
219
		if ($record['pid']==-1)	{
220
			$record = t3lib_BEfunc::getRecord($this->table,$record['t3ver_oid']);
221
		}
222
		$pidValue = $this->table==='pages' ? $this->uid : $record['pid'];
223

    
224
			// Checking access etc.
225
		if (is_array($record) && $TCA[$this->table]['ctrl']['versioningWS'])	{
226
			$this->uid = $record['uid']; 	// Might have changed if new live record was found!
227

    
228
				// Access check!
229
				// The page will show only if there is a valid page and if this page may be viewed by the user
230
			$this->pageinfo = t3lib_BEfunc::readPageAccess($pidValue,$this->perms_clause);
231
			$access = is_array($this->pageinfo) ? 1 : 0;
232

    
233
			if (($pidValue && $access) || ($BE_USER->user['admin'] && !$pidValue))	{
234

    
235
					// JavaScript
236
				$this->doc->JScode.= '
237
					<script language="javascript" type="text/javascript">
238
						script_ended = 0;
239
						function jumpToUrl(URL)	{
240
							window.location.href = URL;
241
						}
242

    
243
						function hlSubelements(origId, verId, over, diffLayer)	{	//
244
							if (over)	{
245
								document.getElementById(\'orig_\'+origId).attributes.getNamedItem("class").nodeValue = \'typo3-ver-hl\';
246
								document.getElementById(\'ver_\'+verId).attributes.getNamedItem("class").nodeValue = \'typo3-ver-hl\';
247
								if (diffLayer)	{
248
									document.getElementById(\'diff_\'+verId).style.visibility = \'visible\';
249
								}
250
							} else {
251
								document.getElementById(\'orig_\'+origId).attributes.getNamedItem("class").nodeValue = \'typo3-ver\';
252
								document.getElementById(\'ver_\'+verId).attributes.getNamedItem("class").nodeValue = \'typo3-ver\';
253
								if (diffLayer)	{
254
									document.getElementById(\'diff_\'+verId).style.visibility = \'hidden\';
255
								}
256
							}
257
						}
258
					</script>
259
				';
260

    
261
					// If another page module was specified, replace the default Page module with the new one
262
				$newPageModule = trim($BE_USER->getTSConfigVal('options.overridePageModule'));
263
				$this->pageModule = t3lib_BEfunc::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
264

    
265
					// Setting publish access permission for workspace:
266
				$this->publishAccess = $BE_USER->workspacePublishAccess($BE_USER->workspace);
267

    
268

    
269
				$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);
270

    
271
				$this->content.=$this->doc->startPage($LANG->getLL('title'));
272
				$this->content.=$this->doc->header($LANG->getLL('title'));
273
				$this->content.=$this->doc->spacer(5);
274
				$this->content.=$this->doc->section('',$headerSection);
275
				$this->content.=$this->doc->divider(5);
276

    
277
					// Render content:
278
				if ($this->id)	{
279
					$this->workspaceMgm();
280
				} else {
281
					$this->versioningMgm();
282
				}
283

    
284
					// ShortCut
285
				if ($BE_USER->mayMakeShortcut())	{
286
					$this->content.=$this->doc->spacer(20).$this->doc->section('',$this->doc->makeShortcutIcon('id',implode(',',array_keys($this->MOD_MENU)),$this->MCONF['name']));
287
				}
288
			}
289

    
290
			$this->content.=$this->doc->spacer(10);
291
		} else {
292
				// If no access or id value, create empty document:
293
			$this->content.=$this->doc->startPage($LANG->getLL('title'));
294
			$this->content.=$this->doc->section($LANG->getLL('clickAPage_header'),$LANG->getLL('clickAPage_content'),0,1);
295
		}
296
	}
297

    
298
	/**
299
	 * Outputs accumulated module content to browser.
300
	 *
301
	 * @return	void
302
	 */
303
	function printContent()	{
304

    
305
		$this->content.=$this->doc->endPage();
306
		echo $this->content;
307
	}
308

    
309

    
310

    
311

    
312

    
313

    
314

    
315

    
316

    
317

    
318
	/******************************
319
	 *
320
	 * Versioning management
321
	 *
322
	 ******************************/
323

    
324
	/**
325
	 * Management of versions for record
326
	 *
327
	 * @return	void
328
	 */
329
	function versioningMgm()	{
330
		global $TCA;
331

    
332
			// Diffing:
333
		$diff_1 = t3lib_div::_POST('diff_1');
334
		$diff_2 = t3lib_div::_POST('diff_2');
335
		if (t3lib_div::_POST('do_diff'))	{
336
			$content='';
337
			$content.='<h3>DIFFING:</h3>';
338
			if ($diff_1 && $diff_2)	{
339
				$diff_1_record = t3lib_BEfunc::getRecord($this->table, $diff_1);
340
				$diff_2_record = t3lib_BEfunc::getRecord($this->table, $diff_2);
341

    
342
				if (is_array($diff_1_record) && is_array($diff_2_record))	{
343
					t3lib_div::loadTCA($this->table);
344
					$t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff');
345

    
346
					$tRows=array();
347
								$tRows[] = '
348
									<tr class="bgColor5 tableheader">
349
										<td>Fieldname:</td>
350
										<td width="98%">Colored diff-view:</td>
351
									</tr>
352
								';
353
					foreach($diff_1_record as $fN => $fV)	{
354
						if ($TCA[$this->table]['columns'][$fN] && $TCA[$this->table]['columns'][$fN]['config']['type']!='passthrough' && !t3lib_div::inList('t3ver_label',$fN))	{
355
							if (strcmp($diff_1_record[$fN],$diff_2_record[$fN]))	{
356

    
357
								$diffres = $t3lib_diff_Obj->makeDiffDisplay(
358
									t3lib_BEfunc::getProcessedValue($this->table,$fN,$diff_2_record[$fN],0,1),
359
									t3lib_BEfunc::getProcessedValue($this->table,$fN,$diff_1_record[$fN],0,1)
360
								);
361

    
362
								$tRows[] = '
363
									<tr class="bgColor4">
364
										<td>'.$fN.'</td>
365
										<td width="98%">'.$diffres.'</td>
366
									</tr>
367
								';
368
							}
369
						}
370
					}
371

    
372
					if (count($tRows)>1)	{
373
						$content.='<table border="0" cellpadding="1" cellspacing="1" width="100%">'.implode('',$tRows).'</table><br/><br/>';
374
					} else {
375
						$content.='Records matches completely on all editable fields!';
376
					}
377
				} else $content.='ERROR: Records could strangely not be found!';
378
			} else {
379
				$content.='ERROR: You didn\'t select two sources for diffing!';
380
			}
381
		}
382

    
383
			// Element:
384
		$record = t3lib_BEfunc::getRecord($this->table,$this->uid);
385
		$recordIcon = t3lib_iconWorks::getIconImage($this->table,$record,$this->doc->backPath,'class="absmiddle"');
386
		$recTitle = t3lib_BEfunc::getRecordTitle($this->table,$record,TRUE);
387

    
388
			// Display versions:
389
		$content.='
390
			'.$recordIcon.$recTitle.'
391
			<form name="theform" action="'.str_replace('&sendToReview=1','',$this->REQUEST_URI).'" method="post">
392
			<table border="0" cellspacing="1" cellpadding="1">';
393
			$content.='
394
				<tr class="bgColor5 tableheader">
395
					<td>&nbsp;</td>
396
					<td>&nbsp;</td>
397
					<td>Title</td>
398
					<td>UID</td>
399
					<td title="t3ver_oid - Reference to live version UID">oid</td>
400
					<td title="t3ver_id - Version number, incremental integer">id</td>
401
					<td title="t3ver_wsid - Workspace ID. There can be only one version of an element per ID (except ID zero).">wsid</td>
402
					<td title="t3ver_state - Special states of a version: 1=Placeholder for &quot;New&quot;. 2=Marked deleted.">state</td>
403
					<td title="t3ver_stage - Publishing stage: Editing (0), review (1), publish (10), rejected (-1).">stage</td>
404
					<td title="t3ver_count - Life cycle counter. Incremented each time element is unpublished.">count</td>
405
					<td>pid</td>
406
					<td>t3ver_label</td>
407
					<td colspan="2"><input type="submit" name="do_diff" value="Diff" /></td>
408
				</tr>';
409

    
410
		$versions = t3lib_BEfunc::selectVersionsOfRecord($this->table, $this->uid, '*', $GLOBALS['BE_USER']->workspace);
411
		foreach($versions as $row)	{
412
			$adminLinks = $this->adminLinks($this->table,$row);
413

    
414
			$content.='
415
				<tr class="'.($row['uid']!=$this->uid ? 'bgColor4' : 'bgColor2 tableheader').'">
416
					<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').'">'.
417
						'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/insert1.gif','width="14" height="14"').' alt="" title="SWAP with current" />'.
418
						'</a>' /* (
419
							$this->table == 'pages' ?
420
							'<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').'">'.
421
						'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/insert2.gif','width="14" height="14"').' alt="" title="Publish page AND content!" />'.
422
						'</a>'.
423
							'<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').'">'.
424
						'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/insert4.gif','width="14" height="14"').' alt="" title="Publish page AND content! - AND ALL SUBPAGES!" />'.
425
						'</a>' : '') */ : '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/blinkarrow_left.gif','width="5" height="9"').' alt="" title="CURRENT ONLINE VERSION!"/>').'</td>
426
					<td nowrap="nowrap">'.$adminLinks.'</td>
427
					<td nowrap="nowrap">'.t3lib_BEfunc::getRecordTitle($this->table,$row,TRUE).'</td>
428
					<td>'.$row['uid'].'</td>
429
					<td>'.$row['t3ver_oid'].'</td>
430
					<td>'.$row['t3ver_id'].'</td>
431
					<td>'.$row['t3ver_wsid'].'</td>
432
					<td>'.$row['t3ver_state'].'</td>
433
					<td>'.$row['t3ver_stage'].'</td>
434
					<td>'.$row['t3ver_count'].'</td>
435
					<td>'.$row['pid'].'</td>
436
					<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>
437
					<td class="version-diff-1"><input type="radio" name="diff_1" value="'.$row['uid'].'"'.($diff_1==$row['uid'] ? ' checked="checked"':'').'/></td>
438
					<td class="version-diff-2"><input type="radio" name="diff_2" value="'.$row['uid'].'"'.($diff_2==$row['uid'] ? ' checked="checked"':'').'/></td>
439
				</tr>';
440

    
441
				// 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;)
442
			if ($this->table == 'pages' && $row['uid']!=$this->uid)	{
443
				$sub = $this->pageSubContent($row['uid']);
444

    
445
				if ($sub)	{
446
					$content.='
447
						<tr>
448
							<td></td>
449
							<td></td>
450
							<td colspan="10">'.$sub.'</td>
451
							<td colspan="2"></td>
452
						</tr>';
453
				}
454
			}
455
		}
456
		$content.='</table></form>';
457

    
458
		$this->content.=$this->doc->section('',$content,0,1);
459

    
460

    
461
			// Create new:
462
		$content='
463

    
464
			<form action="'.$this->doc->backPath.'tce_db.php" method="post">
465
			Label: <input type="text" name="cmd['.$this->table.']['.$this->uid.'][version][label]" /><br/>
466
			'.($this->table == 'pages' ? '<select name="cmd['.$this->table.']['.$this->uid.'][version][treeLevels]">
467
				'.($GLOBALS['BE_USER']->workspaceVersioningTypeAccess(0) ? '<option value="0">Page: Page + content</option>' : '').'
468
				'.($GLOBALS['BE_USER']->workspaceVersioningTypeAccess(1) ? '<option value="100">Branch: All subpages</option>' : '').'
469
				'.($GLOBALS['BE_USER']->workspaceVersioningTypeAccess(-1) ? '<option value="-1">Element: Just record</option>' : '').'
470
			</select>' : '').'
471
			<br/><input type="hidden" name="cmd['.$this->table.']['.$this->uid.'][version][action]" value="new" />
472
			<input type="hidden" name="prErr" value="1" />
473
			<input type="hidden" name="redirect" value="'.htmlspecialchars($this->REQUEST_URI).'" />
474
			<input type="submit" name="_" value="Create new version" />
475

    
476
			</form>
477

    
478
		';
479

    
480
		$this->content.=$this->doc->spacer(15);
481
		$this->content.=$this->doc->section('Create new version',$content,0,1);
482

    
483
	}
484

    
485
	/**
486
	 * Recursively look for children for page version with $pid
487
	 *
488
	 * @param	integer		UID of page record for which to look up sub-elements following that version
489
	 * @param	integer		Counter, do not set (limits to 100 levels)
490
	 * @return	string		Table with content if any
491
	 */
492
	function pageSubContent($pid,$c=0)	{
493
		global $TCA;
494

    
495
		$tableNames = t3lib_div::removeArrayEntryByValue(array_keys($TCA),'pages');
496
		$tableNames[] = 'pages';
497

    
498
		foreach($tableNames as $tN)	{
499
				// Basically list ALL tables - not only those being copied might be found!
500
			#if ($TCA[$tN]['ctrl']['versioning_followPages'] || $tN=='pages')	{
501
				$mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $tN, 'pid='.intval($pid).t3lib_BEfunc::deleteClause($tN), '', ($TCA[$tN]['ctrl']['sortby'] ? $TCA[$tN]['ctrl']['sortby'] : ''));
502

    
503
				if ($GLOBALS['TYPO3_DB']->sql_num_rows($mres))	{
504
					$content.='
505
						<tr>
506
							<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>
507
						</tr>';
508
					while ($subrow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres))	{
509
						$ownVer = $this->lookForOwnVersions($tN,$subrow['uid']);
510
						$content.='
511
							<tr>
512
								<td>'.$this->adminLinks($tN,$subrow).'</td>
513
								<td>'.$subrow['uid'].'</td>
514
								'.($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>').'
515
								<td width="98%">'.t3lib_BEfunc::getRecordTitle($tN,$subrow,TRUE).'</td>
516
							</tr>';
517

    
518
						if ($tN == 'pages' && $c<100)	{
519
							$sub = $this->pageSubContent($subrow['uid'],$c+1);
520

    
521
							if ($sub)	{
522
								$content.='
523
									<tr>
524
										<td></td>
525
										<td></td>
526
										<td></td>
527
										<td width="98%">'.$sub.'</td>
528
									</tr>';
529
							}
530
						}
531
					}
532
				}
533
			#}
534
		}
535

    
536
		return $content ? '<table border="1" cellpadding="1" cellspacing="0" width="100%">'.$content.'</table>' : '';
537
	}
538

    
539
	/**
540
	 * Look for number of versions of a record
541
	 *
542
	 * @param	string		Table name
543
	 * @param	integer		Record uid
544
	 * @return	integer		Number of versions for record, false if none.
545
	 */
546
	function lookForOwnVersions($table,$uid)	{
547
		global $TCA;
548

    
549
		$versions = t3lib_BEfunc::selectVersionsOfRecord($table, $uid, 'uid');
550
		if (is_array($versions))	{
551
			return count($versions);
552
		}
553
		return FALSE;
554
	}
555

    
556
	/**
557
	 * Administrative links for a table / record
558
	 *
559
	 * @param	string		Table name
560
	 * @param	array		Record for which administrative links are generated.
561
	 * @return	string		HTML link tags.
562
	 */
563
	function adminLinks($table,$row)	{
564
		global $BE_USER;
565

    
566
			// Edit link:
567
		$adminLink = '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick('&edit['.$table.']['.$row['uid'].']=edit',$this->doc->backPath)).'">'.
568
						'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/edit2.gif','width="11" height="12"').' alt="" title="Edit"/>'.
569
						'</a>';
570

    
571
			// Delete link:
572
		$adminLink.= '<a href="'.htmlspecialchars($this->doc->issueCommand('&cmd['.$table.']['.$row['uid'].'][delete]=1')).'">'.
573
						'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/garbage.gif','width="11" height="12"').' alt="" title="Delete"/>'.
574
						'</a>';
575

    
576

    
577

    
578
		if ($table == 'pages')	{
579

    
580
				// If another page module was specified, replace the default Page module with the new one
581
			$newPageModule = trim($BE_USER->getTSConfigVal('options.overridePageModule'));
582
			$pageModule = t3lib_BEfunc::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
583

    
584
				// Perform some acccess checks:
585
			$a_wl = $BE_USER->check('modules','web_list');
586
			$a_wp = t3lib_extMgm::isLoaded('cms') && $BE_USER->check('modules',$pageModule);
587

    
588
			$adminLink.='<a href="#" onclick="top.loadEditId('.$row['uid'].');top.goToModule(\''.$pageModule.'\'); return false;">'.
589
						'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,t3lib_extMgm::extRelPath('cms').'layout/layout.gif','width="14" height="12"').' title="" alt="" />'.
590
						'</a>';
591
			$adminLink.='<a href="#" onclick="top.loadEditId('.$row['uid'].');top.goToModule(\'web_list\'); return false;">'.
592
						'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'mod/web/list/list.gif','width="14" height="12"').' title="" alt="" />'.
593
						'</a>';
594

    
595
				// "View page" icon is added:
596
			$adminLink.='<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($row['uid'],$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($row['uid']))).'">'.
597
				'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/zoom.gif','width="12" height="12"').' title="" alt="" />'.
598
				'</a>';
599
		} else {
600
			if ($row['pid']==-1)	{
601
				$getVars = '&ADMCMD_vPrev['.rawurlencode($table.':'.$row['t3ver_oid']).']='.$row['uid'];
602

    
603
					// "View page" icon is added:
604
				$adminLink.='<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($row['_REAL_PID'],$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($row['_REAL_PID']),'','',$getVars)).'">'.
605
					'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/zoom.gif','width="12" height="12"').' title="" alt="" />'.
606
					'</a>';
607
			}
608
		}
609

    
610
		return $adminLink;
611
	}
612

    
613

    
614

    
615

    
616

    
617

    
618

    
619

    
620

    
621

    
622

    
623
	/******************************
624
	 *
625
	 * Workspace management
626
	 *
627
	 ******************************/
628

    
629
	/**
630
	 * Management of workspace for page ID
631
	 * Called when $this->id is set.
632
	 *
633
	 * @return	void
634
	 */
635
	function workspaceMgm()	{
636

    
637
		$menu = '';
638
		if ($GLOBALS['BE_USER']->workspace===0)	{
639
			$menu.= t3lib_BEfunc::getFuncMenu($this->id,'SET[filter]',$this->MOD_SETTINGS['filter'],$this->MOD_MENU['filter']);
640
			$menu.= t3lib_BEfunc::getFuncMenu($this->id,'SET[display]',$this->MOD_SETTINGS['display'],$this->MOD_MENU['display']);
641
		}
642
		if (!$this->details && $GLOBALS['BE_USER']->workspace && !$this->diffOnly)	{
643
			$menu.= t3lib_BEfunc::getFuncCheck($this->id,'SET[diff]',$this->MOD_SETTINGS['diff'],'','','id="checkDiff"').' <label for="checkDiff">Show difference view</label>';
644
		}
645

    
646
		if ($menu)	{
647
			$this->content.=$this->doc->section('',$menu,0,1);
648
		}
649

    
650
			// Perform workspace publishing action if buttons are pressed:
651
		$errors = $this->publishAction();
652

    
653
			// Generate workspace overview:
654
		$WSoverview = $this->displayWorkspaceOverview();
655

    
656
			// Buttons for publish / swap:
657
		$actionLinks = '<br/>';
658
		if ($GLOBALS['BE_USER']->workspace!==0)	{
659
			if ($this->publishAccess)	{
660
				$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?\');"/>';
661
				if ($GLOBALS['BE_USER']->workspaceSwapAccess())	{
662
					$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?\');" />';
663
				}
664
			} else {
665
				$actionLinks.= $this->doc->icons(1).'You are not permitted to publish from this workspace';
666
			}
667
		}
668
		$actionLinks.= '<input type="submit" name="_" value="Refresh" />';
669
		$actionLinks.= '<input type="submit" name="_previewLink" value="Preview Link" />';
670
		$actionLinks.= $this->displayWorkspaceOverview_allStageCmd();
671

    
672
		if ($actionLinks || count($errors))	{
673
			$this->content.= $this->doc->section('',$actionLinks.(count($errors) ? '<h3>Errors:</h3><br/>'.implode('<br/>',$errors).'<hr/>' : ''),0,1);
674
		}
675

    
676
		if (t3lib_div::_POST('_previewLink'))	{
677
			$params = 'id='.$this->id.'&ADMCMD_view=1&ADMCMD_editIcons=1&ADMCMD_previewWS='.$GLOBALS['BE_USER']->workspace;
678
			$previewUrl = t3lib_div::getIndpEnv('TYPO3_SITE_URL').'index.php?ADMCMD_prev='.t3lib_BEfunc::compilePreviewKeyword($params, $GLOBALS['BE_USER']->user['uid']);
679

    
680
			$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);
681
		}
682

    
683
			// Output overview content:
684
		$this->content.= $this->doc->spacer(15);
685
		$this->content.= $this->doc->section($this->details ? 'Details for version' : 'Workspace management', $WSoverview,0,1);
686

    
687
	}
688

    
689
	/**
690
	 * Rendering the overview of versions in the current workspace
691
	 *
692
	 * @return	string		HTML (table)
693
	 * @see typo3/mod/user/ws/index.php for sister function!
694
	 */
695
	function displayWorkspaceOverview()	{
696

    
697
			// Initialize variables:
698
		$this->showWorkspaceCol = $GLOBALS['BE_USER']->workspace===0 && $this->MOD_SETTINGS['display']<=-98;
699

    
700
			// Get usernames and groupnames
701
		$be_group_Array = t3lib_BEfunc::getListGroupNames('title,uid');
702
		$groupArray = array_keys($be_group_Array);
703
		$this->be_user_Array = t3lib_BEfunc::getUserNames();
704
		if (!$GLOBALS['BE_USER']->isAdmin())		$this->be_user_Array = t3lib_BEfunc::blindUserNames($this->be_user_Array,$groupArray,1);
705

    
706
			// Initialize Workspace ID and filter-value:
707
		if ($GLOBALS['BE_USER']->workspace===0)	{
708
			$wsid = $this->details ? -99 : $this->MOD_SETTINGS['display'];		// Set wsid to the value from the menu (displaying content of other workspaces)
709
			$filter = $this->details ? 0 : $this->MOD_SETTINGS['filter'];
710
		} else {
711
			$wsid = $GLOBALS['BE_USER']->workspace;
712
			$filter = 0;
713
		}
714

    
715
			// Initialize workspace object and request all pending versions:
716
		$wslibObj = t3lib_div::makeInstance('wslib');
717

    
718
			// Selecting ALL versions belonging to the workspace:
719
		$versions = $wslibObj->selectVersionsInWorkspace($wsid, $filter, -99, $this->uid);	// $this->uid is the page id of LIVE record.
720

    
721
			// Traverse versions and build page-display array:
722
		$pArray = array();
723
		foreach($versions as $table => $records)	{
724
			foreach($records as $rec)	{
725
				$pageIdField = $table==='pages' ? 't3ver_oid' : 'realpid';
726
				$this->displayWorkspaceOverview_setInPageArray(
727
					$pArray,
728
					$table,
729
					$rec
730
				);
731
			}
732
		}
733

    
734
			// Make header of overview:
735
		$tableRows = array();
736
		if (count($pArray))	{
737
			$tableRows[] = '
738
				<tr class="bgColor5 tableheader">
739
					'.($this->diffOnly?'':'<td nowrap="nowrap" colspan="2">Live Version:</td>').'
740
					<td nowrap="nowrap" colspan="2">Draft Versions:</td>
741
					<td nowrap="nowrap"'.($this->diffOnly?' colspan="2"':' colspan="4"').'>Controls:</td>
742
				</tr>';
743

    
744
				// Add lines from overview:
745
			$tableRows = array_merge($tableRows, $this->displayWorkspaceOverview_list($pArray));
746

    
747
			$table = '<table border="0" cellpadding="0" cellspacing="1" class="lrPadding workspace-overview">'.implode('',$tableRows).'</table>';
748
		} else $table = '';
749

    
750
		$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/>' : '';
751
		$resetDiffOnly = $this->diffOnly ? '<a href="index.php?id='.intval($this->id).'" class="typo3-goBack">Show all information</a><br/><br/>' : '';
752

    
753
		$versionSelector = $GLOBALS['BE_USER']->workspace ? $this->doc->getVersionSelector($this->id) : '';
754

    
755
		return $versionSelector.$linkBack.$resetDiffOnly.$table.$this->markupNewOriginals();
756
	}
757

    
758
	/**
759
	 * Rendering the content for the publish / review overview:
760
	 * (Made for internal recursive calling)
761
	 *
762
	 * @param	array		Storage of the elements to display (see displayWorkspaceOverview() / displayWorkspaceOverview_setInPageArray())
763
	 * @return	array		Table rows, see displayWorkspaceOverview()
764
	 */
765
	function displayWorkspaceOverview_list($pArray)	{
766
		global $TCA;
767

    
768
			// If there ARE elements on this level, print them:
769
		$warnAboutVersions_nonPages = FALSE;
770
		$warnAboutVersions_page = FALSE;
771
		if (is_array($pArray))	{
772
			foreach($pArray as $table => $oidArray)	{
773
				foreach($oidArray as $oid => $recs)	{
774

    
775
						// Get CURRENT online record and icon based on "t3ver_oid":
776
					$rec_on = t3lib_BEfunc::getRecord($table,$oid);
777
					$icon = t3lib_iconWorks::getIconImage($table, $rec_on, $this->doc->backPath,' align="top" title="'.t3lib_BEfunc::getRecordIconAltText($rec_on,$table).'"');
778
					if ($GLOBALS['BE_USER']->workspace===0) {	// Only edit online records if in ONLINE workspace:
779
						$icon = $this->doc->wrapClickMenuOnIcon($icon, $table, $rec_on['uid'], 1, '', '+edit,view,info,delete');
780
					}
781

    
782
						// Online version display:
783
						// Create the main cells which will span over the number of versions there is.
784
					$verLinkUrl = $TCA[$table]['ctrl']['versioningWS'];
785
					$origElement = $icon.
786
						($verLinkUrl ? '<a href="'.htmlspecialchars('index.php?table='.$table.'&uid='.$rec_on['uid']).'">' : '').
787
						t3lib_BEfunc::getRecordTitle($table,$rec_on,TRUE).
788
						($verLinkUrl ? '</a>' : '');
789
					$mainCell_rowSpan = count($recs)>1 ? ' rowspan="'.count($recs).'"' : '';
790
					$mainCell = '
791
								<td align="center"'.$mainCell_rowSpan.'>'.$this->formatVerId($rec_on['t3ver_id']).'</td>
792
								<td nowrap="nowrap"'.$mainCell_rowSpan.'>'.
793
									$origElement.
794
									'###SUB_ELEMENTS###'.	// For substitution with sub-elements, if any.
795
								'</td>';
796

    
797
						// Offline versions display:
798
						// Traverse the versions of the element
799
					foreach($recs as $rec)	{
800

    
801
							// Get the offline version record and icon:
802
						$rec_off = t3lib_BEfunc::getRecord($table,$rec['uid']);
803

    
804
						// Prepare swap-mode values:
805
						if ($table==='pages' && $rec_off['t3ver_swapmode']!=-1)	{
806
							if ($rec_off['t3ver_swapmode']>0)	{
807
								$vType = 'branch';
808
							} else {
809
								$vType = 'page';
810
							}
811
						} else {
812
							$vType = 'element';
813
						}
814
						
815
						// Get icon
816
						$icon = t3lib_iconWorks::getIconImage($table, $rec_off, $this->doc->backPath, ' align="top" title="'.t3lib_BEfunc::getRecordIconAltText($rec_off,$table).'"');
817
						$tempUid = ($table != 'pages' || $vType==='branch' || $GLOBALS['BE_USER']->workspace===0 ? $rec_off['uid'] : $rec_on['uid']);
818
						$icon = $this->doc->wrapClickMenuOnIcon($icon, $table, $tempUid, 1, '', '+edit,' . ($table == 'pages' ? 'view,info,' : '') . 'delete');
819

    
820
							// Prepare diff-code:
821
						if ($this->MOD_SETTINGS['diff'] || $this->diffOnly)	{
822
							$diffCode = '';
823
							list($diffHTML,$diffPct) = $this->createDiffView($table, $rec_off, $rec_on);
824
							if ($rec_on['t3ver_state']==1)	{	// New record:
825
								$diffCode.= $this->doc->icons(1).'New element<br/>';	// TODO Localize?
826
								$diffCode.= $diffHTML;
827
							} elseif ($rec_off['t3ver_state']==2)	{
828
								$diffCode.= $this->doc->icons(2).'Deleted element<br/>';
829
							} else {
830
								$diffCode.= ($diffPct<0 ? 'N/A' : ($diffPct ? $diffPct.'% change:' : ''));
831
								$diffCode.= $diffHTML;
832
							}
833
						} else $diffCode = '';
834

    
835
						switch($vType) {
836
							case 'element':
837
								$swapLabel = ' [Element]';
838
								$swapClass = 'ver-element';
839
								$warnAboutVersions_nonPages = $warnAboutVersions_page;	// Setting this if sub elements are found with a page+content (must be rendered prior to this of course!)
840
							break;
841
							case 'page':
842
								$swapLabel = ' [Page]';
843
								$swapClass = 'ver-page';
844
								$warnAboutVersions_page = !$this->showWorkspaceCol;		// This value is true only if multiple workspaces are shown and we need the opposite here.
845
							break;
846
							case 'branch':
847
								$swapLabel = ' [Branch]';
848
								$swapClass = 'ver-branch';
849
							break;
850
						}
851

    
852
							// Modify main cell based on first version shown:
853
						$subElements = array();
854
						if ($table==='pages' && $rec_off['t3ver_swapmode']!=-1 && $mainCell)	{	// For "Page" and "Branch" swap modes where $mainCell is still carrying content (only first version)
855
							$subElements['on'] = $this->subElements($rec_on['uid'], $rec_off['t3ver_swapmode']);
856
							$subElements['off'] = $this->subElements($rec_off['uid'],$rec_off['t3ver_swapmode'],$rec_on['uid']);
857
						}
858
						$mainCell = str_replace('###SUB_ELEMENTS###', $subElements['on'], $mainCell);
859

    
860
							// Create version element:
861
						$versionsInOtherWS = $this->versionsInOtherWS($table, $rec_on['uid']);
862
						$versionsInOtherWSWarning = $versionsInOtherWS && $GLOBALS['BE_USER']->workspace!==0 ? '<br/>'.$this->doc->icons(2).'Other version(s) in workspace '.$versionsInOtherWS : '';
863
						$multipleWarning = (!$mainCell && $GLOBALS['BE_USER']->workspace!==0? '<br/>'.$this->doc->icons(3).'<b>Multiple versions in same workspace!</b>' : '');
864
						$verWarning = $warnAboutVersions || ($warnAboutVersions_nonPages && $GLOBALS['TCA'][$table]['ctrl']['versioning_followPages'])? '<br/>'.$this->doc->icons(3).'<b>Version inside version!</b>' : '';
865
						$verElement = $icon.
866
							(!$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)).'">' : '').
867
							t3lib_BEfunc::getRecordTitle($table,$rec_off,TRUE).
868
							(!$this->details ? '</a>' : '').
869
							$versionsInOtherWSWarning.
870
							$multipleWarning.
871
							$verWarning;
872

    
873
						$ctrlTable = '
874
								<td nowrap="nowrap">'.$this->showStageChangeLog($table,$rec_off['uid'],$this->displayWorkspaceOverview_stageCmd($table,$rec_off)).'</td>
875
								<td nowrap="nowrap" class="'.$swapClass.'">'.
876
									$this->displayWorkspaceOverview_commandLinks($table,$rec_on,$rec_off,$vType).
877
									htmlspecialchars($swapLabel).
878
									'&nbsp;&nbsp;</td>
879
								'.(!$this->diffOnly?'<td nowrap="nowrap"><b>Lifecycle:</b> '.htmlspecialchars($this->formatCount($rec_off['t3ver_count'])).'</td>'.		// Lifecycle
880
									($this->showWorkspaceCol ? '
881
								<td nowrap="nowrap">&nbsp;&nbsp;<b>Workspace:</b> '.htmlspecialchars($this->formatWorkspace($rec_off['t3ver_wsid'])).'</td>' : ''):'');
882

    
883
						if ($diffCode)	{
884
							$verElement = $verElement.'
885
							<br/><b>Difference to live element:</b>
886
							<table border="0" cellpadding="0" cellspacing="0" class="ver-verElement">
887
								<tr>
888
									<td class="c-diffCell">'.$diffCode.'</td>
889
								</tr>
890
							</table>';
891
						}
892

    
893

    
894
							// Create version cell:
895
						$verCell = '
896
								<td align="center">'.$this->formatVerId($rec_off['t3ver_id']).'</td>
897
								<td nowrap="nowrap">'.
898
									$verElement.
899
									$subElements['off'].
900
									'</td>
901
								';
902

    
903
							// Compile table row:
904
						$tableRows[] = '
905
							<tr class="bgColor4">
906
								'.
907
								($this->diffOnly?'':$mainCell).
908
								$verCell.
909
								$ctrlTable.
910
								'
911
							</tr>';
912

    
913
							// Reset the main cell:
914
						$mainCell = '';
915

    
916
					}
917
				}
918
			}
919
		}
920

    
921
		return $tableRows;
922
	}
923

    
924
	/**
925
	 * Building up of the $pArray
926
	 * (Internal)
927
	 *
928
	 * @param	array		Array that is built up with the page tree structure
929
	 * @param	string		Table name
930
	 * @param	array		Table row
931
	 * @return	void		$pArray is passed by reference and modified internally
932
	 */
933
	function displayWorkspaceOverview_setInPageArray(&$pArray,$table,$row)	{
934
		if (!$this->details || $this->details==$table.':'.$row['uid'])	{
935
			$pArray[$table][$row['t3ver_oid']][] = $row;
936
		}
937
	}
938

    
939
	/**
940
	 * Links to stage change of a version
941
	 *
942
	 * @param	string		Table name
943
	 * @param	array		Offline record (version)
944
	 * @return	string		HTML content, mainly link tags and images.
945
	 */
946
	function displayWorkspaceOverview_allStageCmd()	{
947

    
948
		$table = t3lib_div::_GP('table');
949
		if ($table && $table!='pages')	{
950
			$uid = t3lib_div::_GP('uid');
951
			if ($rec_off = t3lib_BEfunc::getRecordWSOL($table,$uid)) {
952
				$uid = $rec_off['_ORIG_uid'];
953
			}
954
		} else $table = '';
955

    
956
		if ($table)	{
957
			if ($uid && $this->recIndex[$table][$uid])	{
958
				$sId = $this->recIndex[$table][$uid];
959
				switch($sId)	{
960
					case 1:
961
						$label = 'Comment for Reviewer:';
962
					break;
963
					case 10:
964
						$label = 'Comment for Publisher:';
965
					break;
966
				}
967
			} else $sId = 0;
968
		} else {
969
			if (count($this->stageIndex[1]))	{	// Review:
970
				$sId = 1;
971
				$color = '#666666';
972
				$label = 'Sending %s item(s) to review. Comment for Reviewer:';
973
				$titleAttrib = 'Send all to Review';
974
			} elseif(count($this->stageIndex[10]))  {	// Publish:
975
				$sId = 10;
976
				$color = '#6666cc';
977
				$label = 'Approving %s item(s) to publishing. Comment for Publisher:';
978
				$titleAttrib = 'Approve all for Publishing';
979
			} else {
980
				$sId = 0;
981
			}
982
		}
983

    
984
		if ($sId>0)	{
985
			$issueCmd = '';
986
			$itemCount = 0;
987

    
988
			if ($table && $uid && $this->recIndex[$table][$uid])	{
989
				$issueCmd.='&cmd['.$table.']['.$uid.'][version][action]=setStage';
990
				$issueCmd.='&cmd['.$table.']['.$uid.'][version][stageId]='.$this->recIndex[$table][$uid];
991
			} else {
992
				foreach($this->stageIndex[$sId] as $table => $uidArray)	{
993
					$issueCmd.='&cmd['.$table.']['.implode(',',$uidArray).'][version][action]=setStage';
994
					$issueCmd.='&cmd['.$table.']['.implode(',',$uidArray).'][version][stageId]='.$sId;
995
					$itemCount+=count($uidArray);
996
				}
997
			}
998

    
999
			$onClick = 'var commentTxt=window.prompt("'.sprintf($label,$itemCount).'","");
1000
							if (commentTxt!=null) {window.location.href="'.$this->doc->issueCommand($issueCmd,$this->REQUEST_URI).'&generalComment="+escape(commentTxt);}';
1001

    
1002
			if (t3lib_div::_GP('sendToReview'))	{
1003
				$onClick.= ' else {window.location.href = "'.$this->REQUEST_URI.'"}';
1004
				$actionLinks.=
1005
					$this->doc->wrapScriptTags($onClick);
1006
			} else {
1007
				$onClick.= ' return false;';
1008
				$actionLinks.=
1009
					'<input type="submit" name="_" value="'.htmlspecialchars($titleAttrib).'" onclick="'.htmlspecialchars($onClick).'" />';
1010
			}	
1011
		} elseif (t3lib_div::_GP('sendToReview'))	{
1012
			$onClick = 'window.location.href = "'.$this->REQUEST_URI.'";';
1013
			$actionLinks.=
1014
				$this->doc->wrapScriptTags($onClick);
1015
		} else $actionLinks = '';
1016

    
1017
		return $actionLinks;
1018
	}
1019

    
1020

    
1021

    
1022

    
1023

    
1024

    
1025
	/**************************************
1026
	 *
1027
	 * Helper functions (REDUNDANT FROM user/ws/index.php - someone could refactor this...)
1028
	 *
1029
	 *************************************/
1030

    
1031
	/**
1032
	 * Formatting the version number for HTML output
1033
	 *
1034
	 * @param	integer		Version number
1035
	 * @return	string		Version number for output
1036
	 */
1037
	function formatVerId($verId)	{
1038
		return '1.'.$verId;
1039
	}
1040

    
1041
	/**
1042
	 * Formatting workspace ID into a visual label
1043
	 *
1044
	 * @param	integer		Workspace ID
1045
	 * @return	string		Workspace title
1046
	 */
1047
	function formatWorkspace($wsid)	{
1048

    
1049
			// Render, if not cached:
1050
		if (!isset($this->formatWorkspace_cache[$wsid]))	{
1051
			switch($wsid)	{
1052
				case -1:
1053
					$this->formatWorkspace_cache[$wsid] = '[Offline]';
1054
				break;
1055
				case 0:
1056
					$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...
1057
				break;
1058
				default:
1059
					list($titleRec) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('title','sys_workspace','uid='.intval($wsid).t3lib_BEfunc::deleteClause('sys_workspace'));
1060
					$this->formatWorkspace_cache[$wsid] = '['.$wsid.'] '.$titleRec['title'];
1061
				break;
1062
			}
1063
		}
1064

    
1065
		return $this->formatWorkspace_cache[$wsid];
1066
	}
1067

    
1068
	/**
1069
	 * Format publishing count for version (lifecycle state)
1070
	 *
1071
	 * @param	integer		t3ver_count value (number of times it has been online)
1072
	 * @return	string		String translation of count.
1073
	 */
1074
	function formatCount($count)	{
1075

    
1076
			// Render, if not cached:
1077
		if (!isset($this->formatCount_cache[$count]))	{
1078
			switch($count)	{
1079
				case 0:
1080
					$this->formatCount_cache[$count] = 'Draft';
1081
				break;
1082
				case 1:
1083
					$this->formatCount_cache[$count] = 'Archive';
1084
				break;
1085
				default:
1086
					$this->formatCount_cache[$count] = 'Published '.$count.' times';
1087
				break;
1088
			}
1089
		}
1090

    
1091
		return $this->formatCount_cache[$count];
1092
	}
1093

    
1094
	/**
1095
	 * Looking for versions of a record in other workspaces than the current
1096
	 *
1097
	 * @param	string		Table name
1098
	 * @param	integer		Record uid
1099
	 * @return	string		List of other workspace IDs
1100
	 */
1101
	function versionsInOtherWS($table,$uid)	{
1102

    
1103
			// Check for duplicates:
1104
			// Select all versions of record NOT in this workspace:
1105
		$rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
1106
			't3ver_wsid',
1107
			$table,
1108
			'pid=-1
1109
				AND t3ver_oid='.intval($uid).'
1110
				AND t3ver_wsid!='.intval($GLOBALS['BE_USER']->workspace).'
1111
				AND (t3ver_wsid=-1 OR t3ver_wsid>0)'.
1112
				t3lib_BEfunc::deleteClause($table),
1113
			'',
1114
			't3ver_wsid',
1115
			'',
1116
			't3ver_wsid'
1117
		);
1118
		if (count($rows))	{
1119
			return implode(',',array_keys($rows));
1120
		}
1121
	}
1122

    
1123
	/**
1124
	 * Looks up stage changes for version and displays a formatted view on mouseover.
1125
	 *
1126
	 * @param	string		Table name
1127
	 * @param	integer		Record ID
1128
	 * @param	string		HTML string to wrap the mouseover around (should be stage change links)
1129
	 * @return	string		HTML code.
1130
	 */
1131
	function showStageChangeLog($table,$id,$stageCommands)	{
1132
		$rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
1133
			'log_data,tstamp,userid',
1134
			'sys_log',
1135
			'action=6 and details_nr=30
1136
				AND tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($table,'sys_log').'
1137
				AND recuid='.intval($id)
1138
		);
1139

    
1140
		$entry = array();
1141
		foreach($rows as $dat)	{
1142
			$data = unserialize($dat['log_data']);
1143
			$username = $this->be_user_Array[$dat['userid']] ? $this->be_user_Array[$dat['userid']]['username'] : '['.$dat['userid'].']';
1144

    
1145
			switch($data['stage'])	{
1146
				case 1:
1147
					$text = 'sent element to "Review"';
1148
				break;
1149
				case 10:
1150
					$text = 'approved for "Publish"';
1151
				break;
1152
				case -1:
1153
					$text = 'rejected element!';
1154
				break;
1155
				case 0:
1156
					$text = 'reset to "Editing"';
1157
				break;
1158
				default:
1159
					$text = '[undefined]';
1160
				break;
1161
			}
1162
			$text = t3lib_BEfunc::dateTime($dat['tstamp']).': "'.$username.'" '.$text;
1163
			$text.= ($data['comment']?'<br/>User Comment: <em>'.htmlspecialchars($data['comment']).'</em>':'');
1164

    
1165
			$entry[] = $text;
1166
		}
1167

    
1168
		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>'.
1169
				'<div class="logLayer" style="visibility: hidden; position: absolute;" id="log_'.$table.$id.'">'.implode('<hr/>',array_reverse($entry)).'</div>' : $stageCommands;
1170
	}
1171

    
1172
	/**
1173
	 * Creates display of sub elements of a page when the swap mode is either "Page" or "Branch" (0 / ALL)
1174
	 *
1175
	 * @param	integer		Page uid (for either online or offline version, but it MUST have swapmode/treeLevel set to >0 (not -1 indicating element versioning)
1176
	 * @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!)
1177
	 * @param	integer		For offline versions; This is t3ver_oid, the original ID of the online page.
1178
	 * @return	string		HTML content.
1179
	 */
1180
	function subElements($uid,$treeLevel,$origId=0)	{
1181
		global $TCA;
1182

    
1183
		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:
1184
			return '<br/>
1185
					<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/ol/joinbottom.gif','width="18" height="16"').' align="top" alt="" title="" />'.
1186
					($origId ?
1187
						'<a href="'.htmlspecialchars($this->doc->backPath.t3lib_extMgm::extRelPath('version').'cm1/index.php?id='.$uid.'&details='.rawurlencode('pages:'.$uid).'&returnUrl='.rawurlencode($this->REQUEST_URI)).'">'.
1188
						'<span class="typo3-dimmed"><em>[Sub elements, click for details]</em><span></a>' :
1189
						'<span class="typo3-dimmed"><em>[Sub elements]</em><span>');
1190
		} else {	// For an offline workspace, show sub elements:
1191

    
1192
			$tCell = array();
1193

    
1194
				// Find records that follow pages when swapping versions:
1195
			$recList = array();
1196
			foreach($TCA as $tN => $tCfg)	{
1197
				if ($tN!='pages' && ($treeLevel>0 || $TCA[$tN]['ctrl']['versioning_followPages']))	{
1198
					$this->subElements_getNonPageRecords($tN, $uid, $recList);
1199
				}
1200
			}
1201

    
1202
				// Render records collected above:
1203
			$elCount = count($recList)-1;
1204
			foreach($recList as $c => $comb)	{
1205
				list($tN,$rec) = $comb;
1206

    
1207
				$this->subElements_renderItem(
1208
					$tCell,
1209
					$tN,
1210
					$uid,
1211
					$rec,
1212
					$origId,
1213
					$c==$elCount && $treeLevel==0 ? 1 : 0,		// If true, will show bottom-join icon.
1214
					''
1215
				);
1216
			}
1217

    
1218
				// For branch, dive into the subtree:
1219
			if ($treeLevel>0) {
1220

    
1221
					// Drawing tree:
1222
				$tree = t3lib_div::makeInstance('t3lib_pageTree');
1223
				$tree->init('AND '.$GLOBALS['BE_USER']->getPagePermsClause(1));
1224
				$tree->makeHTML = 2;		// 2=Also rendering depth-data into the result array
1225
				$tree->getTree($uid, 99, '');
1226

    
1227
					// Traverse page tree:
1228
				foreach($tree->tree as $data)	{
1229

    
1230
						// Render page in table cell:
1231
					$this->subElements_renderItem(
1232
						$tCell,
1233
						'pages',
1234
						$uid,
1235
						t3lib_BEfunc::getRecord('pages',$data['row']['uid']),	// Needs all fields, at least more than what is given in $data['row']...
1236
						$origId,
1237
						2,		// 2=the join icon and icon for the record is not rendered for pages (where all is in $data['HTML']
1238
						$data['HTML']
1239
					);
1240

    
1241
						// Find all records from page and collect in $recList:
1242
					$recList = array();
1243
					foreach($TCA as $tN => $tCfg)	{
1244
						if ($tN!=='pages')	{
1245
							$this->subElements_getNonPageRecords($tN, $data['row']['uid'], $recList);
1246
						}
1247
					}
1248

    
1249
						// Render records collected above:
1250
					$elCount = count($recList)-1;
1251
					foreach($recList as $c => $comb)	{
1252
						list($tN,$rec) = $comb;
1253

    
1254
						$this->subElements_renderItem(
1255
							$tCell,
1256
							$tN,
1257
							$uid,
1258
							$rec,
1259
							$origId,
1260
							$c==$elCount?1:0,	// If true, will show bottom-join icon.
1261
							$data['HTML_depthData']
1262
						);
1263
					}
1264
				}
1265
			}
1266

    
1267
			return '
1268
					<!-- Sub-element tree for versions -->
1269
					<table border="0" cellpadding="0" cellspacing="1" class="ver-subtree">
1270
						'.implode('',$tCell).'
1271
					</table>';
1272
		}
1273
	}
1274

    
1275
	/**
1276
	 * Select records from a table and add them to recList
1277
	 *
1278
	 * @param	string		Table name (from TCA)
1279
	 * @param	integer		PID to select records from
1280
	 * @param	array		Array where records are accumulated, passed by reference
1281
	 * @return	void
1282
	 */
1283
	function subElements_getNonPageRecords($tN, $uid, &$recList)	{
1284
		global $TCA;
1285

    
1286
		$records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
1287
			'*',
1288
			$tN,
1289
			'pid='.intval($uid).
1290
				($TCA[$tN]['ctrl']['versioningWS'] ? ' AND t3ver_state=0' : '').
1291
				t3lib_BEfunc::deleteClause($tN),
1292
			'',
1293
			$TCA[$tN]['ctrl']['sortby'] ? $TCA[$tN]['ctrl']['sortby'] : $GLOBALS['TYPO3_DB']->stripOrderBy($TCA[$tN]['ctrl']['default_sortby'])
1294
		);
1295

    
1296
		foreach($records as $rec)	{
1297
			$recList[] = array($tN,$rec);
1298
		}
1299
	}
1300

    
1301
	/**
1302
	 * Render a single item in a subelement list into a table row:
1303
	 *
1304
	 * @param	array		Table rows, passed by reference
1305
	 * @param	string		Table name
1306
	 * @param	integer		Page uid for which the subelements are selected/shown
1307
	 * @param	array		Row of element in list
1308
	 * @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.
1309
	 * @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)
1310
	 * @param	string		Prefix HTML data (icons for tree rendering)
1311
	 * @return	void		(Content accumulated in $tCell!)
1312
	 */
1313
	function subElements_renderItem(&$tCell,$tN,$uid,$rec,$origId,$iconMode,$HTMLdata)	{
1314
		global $TCA;
1315

    
1316
			// Initialize:
1317
		$origUidFields = $TCA[$tN]['ctrl']['origUid'];
1318
		$diffCode = '';
1319

    
1320
		if ($origUidFields)	{	// If there is a field for this table with original uids we will use that to connect records:
1321
			if (!$origId)	{	// In case we are displaying the online originals:
1322
				$this->targets['orig_'.$uid.'_'.$tN.'_'.$rec['uid']] = $rec;	// Build up target array (important that
1323
				$tdParams =  ' id="orig_'.$uid.'_'.$tN.'_'.$rec['uid'].'" class="typo3-ver"';		// Setting ID of the table row
1324
			} else {	// Version branch:
1325
				if ($this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]])	{	// If there IS a corresponding original record...:
1326

    
1327
						// Prepare Table row parameters:
1328
					$tdParams =  ' onmouseover="hlSubelements(\''.$origId.'_'.$tN.'_'.$rec[$origUidFields].'\', \''.$uid.'_'.$tN.'_'.$rec[$origUidFields].'\', 1, '.($this->MOD_SETTINGS['diff']==2?1:0).');"'.
1329
								' onmouseout="hlSubelements(\''.$origId.'_'.$tN.'_'.$rec[$origUidFields].'\', \''.$uid.'_'.$tN.'_'.$rec[$origUidFields].'\', 0, '.($this->MOD_SETTINGS['diff']==2?1:0).');"'.
1330
								' id="ver_'.$uid.'_'.$tN.'_'.$rec[$origUidFields].'" class="typo3-ver"';
1331

    
1332
						// Create diff view:
1333
					if ($this->MOD_SETTINGS['diff'])	{
1334
						list($diffHTML,$diffPct) = $this->createDiffView($tN, $rec, $this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]]);
1335

    
1336
						if ($this->MOD_SETTINGS['diff']==2)	{
1337
							$diffCode =
1338
								($diffPct ? '<span class="nobr">'.$diffPct.'% change</span>' : '-').
1339
								'<div style="visibility: hidden; position: absolute;" id="diff_'.$uid.'_'.$tN.'_'.$rec[$origUidFields].'" class="diffLayer">'.
1340
								$diffHTML.
1341
								'</div>';
1342
						} else {
1343
							$diffCode =
1344
								($diffPct<0 ? 'N/A' : ($diffPct ? $diffPct.'% change:' : '')).
1345
								$diffHTML;
1346
						}
1347
					}
1348

    
1349
						// Unsetting the target fields allows us to mark all originals without a version in the subtree (see ->markupNewOriginals())
1350
					unset($this->targets['orig_'.$origId.'_'.$tN.'_'.$rec[$origUidFields]]);
1351
				} else {	// No original record, so must be new:
1352
					$tdParams =  ' class="typo3-ver-new"';
1353
				}
1354
			}
1355
		} else {	// If no original uid column is supported for this table we are forced NOT to display any diff or highlighting.
1356
			$tdParams = ' class="typo3-ver-noComp"';
1357
		}
1358

    
1359
			// Compile the cell:
1360
		$tCell[] = '
1361
						<tr'.$tdParams.'>
1362
							<td class="iconTitle">'.
1363
								$HTMLdata.
1364
								($iconMode < 2 ?
1365
									'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/ol/join'.($iconMode ? 'bottom' : '').'.gif','width="18" height="16"').' alt="" />'.
1366
									t3lib_iconWorks::getIconImage($tN, $rec, $this->doc->backPath,'') : '').
1367
								t3lib_BEfunc::getRecordTitle($tN, $rec, TRUE).
1368
							'</td>
1369
							<td class="cmdCell">'.
1370
								$this->displayWorkspaceOverview_commandLinksSub($tN,$rec,$origId).
1371
							'</td>'.($origId ? '<td class="diffCell">'.
1372
								$diffCode.
1373
							'</td>':'').'
1374
						</tr>';
1375
	}
1376

    
1377
	/**
1378
	 * JavaScript code to mark up new records that are online (in sub element lists)
1379
	 *
1380
	 * @return	string		HTML javascript section
1381
	 */
1382
	function markupNewOriginals()	{
1383

    
1384
		if (count($this->targets))	{
1385
			$scriptCode = '';
1386
			foreach($this->targets as $key => $rec)	{
1387
				$scriptCode.='
1388
					document.getElementById(\''.$key.'\').attributes.getNamedItem("class").nodeValue = \'typo3-ver-new\';
1389
				';
1390
			}
1391

    
1392
			return $this->doc->wrapScriptTags($scriptCode);
1393
		}
1394
	}
1395

    
1396
	/**
1397
	 * Create visual difference view of two records. Using t3lib_diff library
1398
	 *
1399
	 * @param	string		Table name
1400
	 * @param	array		New version record (green)
1401
	 * @param	array		Old version record (red)
1402
	 * @return	array		Array with two keys (0/1) with HTML content / percentage integer (if -1, then it means N/A) indicating amount of change
1403
	 */
1404
	function createDiffView($table, $diff_1_record, $diff_2_record)	{
1405
		global $TCA;
1406

    
1407
			// Initialize:
1408
		$pctChange = 'N/A';
1409

    
1410
			// Check that records are arrays:
1411
		if (is_array($diff_1_record) && is_array($diff_2_record))	{
1412

    
1413
				// Load full table description and initialize diff-object:
1414
			t3lib_div::loadTCA($table);
1415
			$t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff');
1416

    
1417
				// Add header row:
1418
			$tRows = array();
1419
			$tRows[] = '
1420
				<tr class="bgColor5 tableheader">
1421
					<td>Fieldname:</td>
1422
					<td width="98%" nowrap="nowrap">Colored diff-view:</td>
1423
				</tr>
1424
			';
1425

    
1426
				// Initialize variables to pick up string lengths in:
1427
			$allStrLen = 0;
1428
			$diffStrLen = 0;
1429

    
1430
				// Traversing the first record and process all fields which are editable:
1431
			foreach($diff_1_record as $fN => $fV)	{
1432
				if ($TCA[$table]['columns'][$fN] && $TCA[$table]['columns'][$fN]['config']['type']!='passthrough' && !t3lib_div::inList('t3ver_label',$fN))	{
1433

    
1434
						// Check if it is files:
1435
					$isFiles = FALSE;
1436
					if (strcmp(trim($diff_1_record[$fN]),trim($diff_2_record[$fN])) &&
1437
							$TCA[$table]['columns'][$fN]['config']['type']=='group' &&
1438
							$TCA[$table]['columns'][$fN]['config']['internal_type']=='file')	{
1439

    
1440
							// Initialize:
1441
						$uploadFolder = $TCA[$table]['columns'][$fN]['config']['uploadfolder'];
1442
						$files1 = array_flip(t3lib_div::trimExplode(',', $diff_1_record[$fN],1));
1443
						$files2 = array_flip(t3lib_div::trimExplode(',', $diff_2_record[$fN],1));
1444

    
1445
							// Traverse filenames and read their md5 sum:
1446
						foreach($files1 as $filename => $tmp)	{
1447
							$files1[$filename] = @is_file(PATH_site.$uploadFolder.'/'.$filename) ? md5(t3lib_div::getUrl(PATH_site.$uploadFolder.'/'.$filename)) : $filename;
1448
						}
1449
						foreach($files2 as $filename => $tmp)	{
1450
							$files2[$filename] = @is_file(PATH_site.$uploadFolder.'/'.$filename) ? md5(t3lib_div::getUrl(PATH_site.$uploadFolder.'/'.$filename)) : $filename;
1451
						}
1452

    
1453
							// Implode MD5 sums and set flag:
1454
						$diff_1_record[$fN] = implode(' ',$files1);
1455
						$diff_2_record[$fN] = implode(' ',$files2);
1456
						$isFiles = TRUE;
1457
					}
1458

    
1459
						// If there is a change of value:
1460
					if (strcmp(trim($diff_1_record[$fN]),trim($diff_2_record[$fN])))	{
1461

    
1462

    
1463
							// Get the best visual presentation of the value and present that:
1464
						$val1 = t3lib_BEfunc::getProcessedValue($table,$fN,$diff_2_record[$fN],0,1);
1465
						$val2 = t3lib_BEfunc::getProcessedValue($table,$fN,$diff_1_record[$fN],0,1);
1466

    
1467
							// Make diff result and record string lenghts:
1468
						$diffres = $t3lib_diff_Obj->makeDiffDisplay($val1,$val2,$isFiles?'div':'span');
1469
						$diffStrLen+= $t3lib_diff_Obj->differenceLgd;
1470
						$allStrLen+= strlen($val1.$val2);
1471

    
1472
							// If the compared values were files, substituted MD5 hashes:
1473
						if ($isFiles)	{
1474
							$allFiles = array_merge($files1,$files2);
1475
							foreach($allFiles as $filename => $token)	{
1476
								if (strlen($token)==32 && strstr($diffres,$token))	{
1477
									$filename =
1478
										t3lib_BEfunc::thumbCode(array($fN=>$filename),$table,$fN,$this->doc->backPath).
1479
										$filename;
1480
									$diffres = str_replace($token,$filename,$diffres);
1481
								}
1482
							}
1483
						}
1484

    
1485
							// Add table row with result:
1486
						$tRows[] = '
1487
							<tr class="bgColor4">
1488
								<td>'.htmlspecialchars($GLOBALS['LANG']->sL(t3lib_BEfunc::getItemLabel($table,$fN))).'</td>
1489
								<td width="98%">'.$diffres.'</td>
1490
							</tr>
1491
						';
1492
					} else {
1493
							// Add string lengths even if value matched - in this was the change percentage is not high if only a single field is changed:
1494
						$allStrLen+=strlen($diff_1_record[$fN].$diff_2_record[$fN]);
1495
					}
1496
				}
1497
			}
1498

    
1499
				// Calculate final change percentage:
1500
			$pctChange = $allStrLen ? ceil($diffStrLen*100/$allStrLen) : -1;
1501

    
1502
				// Create visual representation of result:
1503
			if (count($tRows)>1)	{
1504
				$content.= '<table border="0" cellpadding="1" cellspacing="1" class="diffTable">'.implode('',$tRows).'</table>';
1505
			} else {
1506
				$content.= '<span class="nobr">'.$this->doc->icons(1).'Complete match on editable fields.</span>';
1507
			}
1508
		} else $content.= $this->doc->icons(3).'ERROR: Records could strangely not be found!';
1509

    
1510
			// Return value:
1511
		return array($content,$pctChange);
1512
	}
1513

    
1514
	/**
1515
	 * Links to stage change of a version
1516
	 *
1517
	 * @param	string		Table name
1518
	 * @param	array		Offline record (version)
1519
	 * @return	string		HTML content, mainly link tags and images.
1520
	 */
1521
	function displayWorkspaceOverview_stageCmd($table,&$rec_off)	{
1522
#debug($rec_off['t3ver_stage']);
1523
		switch((int)$rec_off['t3ver_stage'])	{
1524
			case 0:
1525
				$sId = 1;
1526
				$sLabel = 'Editing';
1527
				$color = '#666666';
1528
 				$label = 'Comment for Reviewer:';
1529
				$titleAttrib = 'Send to Review';
1530
			break;
1531
			case 1:
1532
				$sId = 10;
1533
				$sLabel = 'Review';
1534
				$color = '#6666cc';
1535
				$label = 'Comment for Publisher:';
1536
				$titleAttrib = 'Approve for Publishing';
1537
			break;
1538
			case 10:
1539
				$sLabel = 'Publish';
1540
				$color = '#66cc66';
1541
			break;
1542
			case -1:
1543
				$sLabel = $this->doc->icons(2).'Rejected';
1544
				$sId = 0;
1545
				$color = '#ff0000';
1546
				$label = 'Comment:';
1547
				$titleAttrib = 'Reset stage';
1548
			break;
1549
			default:
1550
				$sLabel = 'Undefined';
1551
				$sId = 0;
1552
				$color = '';
1553
			break;
1554
		}
1555
#debug($sId);
1556

    
1557
		$raiseOk = !$GLOBALS['BE_USER']->workspaceCannotEditOfflineVersion($table,$rec_off);
1558

    
1559
		if ($raiseOk && $rec_off['t3ver_stage']!=-1)	{
1560
			$onClick = 'var commentTxt=window.prompt("Please explain why you reject:","");
1561
							if (commentTxt!=null) {window.location.href="'.$this->doc->issueCommand(
1562
							'&cmd['.$table.']['.$rec_off['uid'].'][version][action]=setStage'.
1563
							'&cmd['.$table.']['.$rec_off['uid'].'][version][stageId]=-1'
1564
							).'&cmd['.$table.']['.$rec_off['uid'].'][version][comment]="+escape(commentTxt);}'.
1565
							' return false;';
1566
				// Reject:
1567
			$actionLinks.=
1568
				'<a href="#" onclick="'.htmlspecialchars($onClick).'">'.
1569
				'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/down.gif','width="14" height="14"').' alt="" align="top" title="Reject" />'.
1570
				'</a>';
1571
		} else {
1572
				// Reject:
1573
			$actionLinks.=
1574
				'<img src="'.$this->doc->backPath.'gfx/clear.gif" width="14" height="14" alt="" align="top" title="" />';
1575
		}
1576

    
1577
		$actionLinks.= '<span style="background-color: '.$color.'; color: white;">'.$sLabel.'</span>';
1578

    
1579
			// Raise
1580
		if ($raiseOk)	{
1581
			$onClick = 'var commentTxt=window.prompt("'.$label.'","");
1582
							if (commentTxt!=null) {window.location.href="'.$this->doc->issueCommand(
1583
							'&cmd['.$table.']['.$rec_off['uid'].'][version][action]=setStage'.
1584
							'&cmd['.$table.']['.$rec_off['uid'].'][version][stageId]='.$sId
1585
							).'&cmd['.$table.']['.$rec_off['uid'].'][version][comment]="+escape(commentTxt);}'.
1586
							' return false;';
1587
			if ($rec_off['t3ver_stage']!=10)	{
1588
				$actionLinks.=
1589
					'<a href="#" onclick="'.htmlspecialchars($onClick).'">'.
1590
					'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/up.gif','width="14" height="14"').' alt="" align="top" title="'.htmlspecialchars($titleAttrib).'" />'.
1591
					'</a>';
1592

    
1593
				$this->stageIndex[$sId][$table][] = $rec_off['uid'];
1594
				$this->recIndex[$table][$rec_off['uid']] = $sId;
1595
			}
1596
		}
1597
		return $actionLinks;
1598
	}
1599

    
1600
	/**
1601
	 * Links to publishing etc of a version
1602
	 *
1603
	 * @param	string		Table name
1604
	 * @param	array		Online record
1605
	 * @param	array		Offline record (version)
1606
	 * @param	string		Swap type, "branch", "page" or "element"
1607
	 * @return	string		HTML content, mainly link tags and images.
1608
	 */
1609
	function displayWorkspaceOverview_commandLinks($table,&$rec_on,&$rec_off,$vType)	{
1610
		if ($this->publishAccess && (!($GLOBALS['BE_USER']->workspaceRec['publish_access']&1) || (int)$rec_off['t3ver_stage']===10))	{
1611
			$actionLinks =
1612
				'<a href="'.htmlspecialchars($this->doc->issueCommand(
1613
						'&cmd['.$table.']['.$rec_on['uid'].'][version][action]=swap'.
1614
						'&cmd['.$table.']['.$rec_on['uid'].'][version][swapWith]='.$rec_off['uid']
1615
						)).'">'.
1616
				'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/insert1.gif','width="14" height="14"').' alt="" align="top" title="Publish" />'.
1617
				'</a>';
1618
			if ($GLOBALS['BE_USER']->workspaceSwapAccess() && (int)$rec_on['t3ver_state']!==1 && (int)$rec_off['t3ver_state']!==2)	{
1619
				$actionLinks.=
1620
					'<a href="'.htmlspecialchars($this->doc->issueCommand(
1621
							'&cmd['.$table.']['.$rec_on['uid'].'][version][action]=swap'.
1622
							'&cmd['.$table.']['.$rec_on['uid'].'][version][swapWith]='.$rec_off['uid'].
1623
							'&cmd['.$table.']['.$rec_on['uid'].'][version][swapIntoWS]=1'
1624
							)).'">'.
1625
					'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/swap.png','width="14" height="14"').' alt="" align="top" title="Swap" />'.
1626
					'</a>';
1627
			}
1628
		}
1629

    
1630
		if (!$GLOBALS['BE_USER']->workspaceCannotEditOfflineVersion($table,$rec_off))	{
1631
				// Release
1632
			$actionLinks.=
1633
				'<a href="'.htmlspecialchars($this->doc->issueCommand('&cmd['.$table.']['.$rec_off['uid'].'][version][action]=clearWSID')).'" onclick="return confirm(\'Remove from workspace?\');">'.
1634
				'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/group_clear.gif','width="14" height="14"').' alt="" align="top" title="Remove from workspace" />'.
1635
				'</a>';
1636

    
1637
				// Edit
1638
			if ($table==='pages' && $vType!=='element')	{
1639
				$tempUid = ($vType==='branch' || $GLOBALS['BE_USER']->workspace===0 ? $rec_off['uid'] : $rec_on['uid']);
1640
				$actionLinks.=
1641
					'<a href="#" onclick="top.loadEditId('.$tempUid.');top.goToModule(\''.$this->pageModule.'\'); return false;">'.
1642
					'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,t3lib_extMgm::extRelPath('cms').'layout/layout.gif','width="14" height="12"').' title="Edit page" alt="" />'.
1643
					'</a>';
1644
			} else {
1645
				$params = '&edit['.$table.']['.$rec_off['uid'].']=edit';
1646
				$actionLinks.=
1647
					'<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick($params,$this->doc->backPath)).'">'.
1648
					'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/edit2.gif','width="12" height="12"').' title="Edit element" alt="" />'.
1649
					'</a>';
1650
			}
1651
		}
1652

    
1653
			// History/Log
1654
		$actionLinks.=
1655
			'<a href="'.htmlspecialchars($this->doc->backPath.'show_rechis.php?element='.rawurlencode($table.':'.$rec_off['uid']).'&returnUrl='.rawurlencode($this->REQUEST_URI)).'">'.
1656
			'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/history2.gif','width="13" height="12"').' title="Show Log" alt="" />'.
1657
			'</a>';
1658

    
1659
			// View
1660
		if ($table==='pages')	{
1661
			$tempUid = ($vType==='branch' || $GLOBALS['BE_USER']->workspace===0 ? $rec_off['uid'] : $rec_on['uid']);
1662
			$actionLinks.=
1663
				'<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($tempUid,$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($tempUid))).'">'.
1664
				'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/zoom.gif','width="12" height="12"').' title="" alt="" />'.
1665
				'</a>';
1666
		}
1667

    
1668
		return $actionLinks;
1669
	}
1670

    
1671
	/**
1672
	 * Links to publishing etc of a version
1673
	 *
1674
	 * @param	string		Table name
1675
	 * @param	array		Record
1676
	 * @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.
1677
	 * @return	string		HTML content, mainly link tags and images.
1678
	 */
1679
	function displayWorkspaceOverview_commandLinksSub($table,$rec,$origId)	{
1680
		$uid = $rec['uid'];
1681
		if ($origId || $GLOBALS['BE_USER']->workspace===0)	{
1682
			if (!$GLOBALS['BE_USER']->workspaceCannotEditRecord($table,$rec))	{
1683
					// Edit
1684
				if ($table==='pages')	{
1685
					$actionLinks.=
1686
						'<a href="#" onclick="top.loadEditId('.$uid.');top.goToModule(\''.$this->pageModule.'\'); return false;">'.
1687
						'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,t3lib_extMgm::extRelPath('cms').'layout/layout.gif','width="14" height="12"').' title="Edit page" alt="" />'.
1688
						'</a>';
1689
				} else {
1690
					$params = '&edit['.$table.']['.$uid.']=edit';
1691
					$actionLinks.=
1692
						'<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::editOnClick($params,$this->doc->backPath)).'">'.
1693
						'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/edit2.gif','width="12" height="12"').' title="Edit element" alt="" />'.
1694
						'</a>';
1695
				}
1696
			}
1697

    
1698
				// History/Log
1699
			$actionLinks.=
1700
				'<a href="'.htmlspecialchars($this->doc->backPath.'show_rechis.php?element='.rawurlencode($table.':'.$uid).'&returnUrl='.rawurlencode($this->REQUEST_URI)).'">'.
1701
				'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/history2.gif','width="13" height="12"').' title="Show Log" alt="" />'.
1702
				'</a>';
1703
		}
1704

    
1705
			// View
1706
		if ($table==='pages')	{
1707
			$actionLinks.=
1708
				'<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($uid,$this->doc->backPath,t3lib_BEfunc::BEgetRootLine($uid))).'">'.
1709
				'<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/zoom.gif','width="12" height="12"').' title="" alt="" />'.
1710
				'</a>';
1711
		}
1712

    
1713
		return $actionLinks;
1714
	}
1715

    
1716

    
1717

    
1718

    
1719

    
1720

    
1721

    
1722

    
1723

    
1724
	/**********************************
1725
	 *
1726
	 * Processing
1727
	 *
1728
	 **********************************/
1729

    
1730
	/**
1731
	 * Will publish workspace if buttons are pressed
1732
	 *
1733
	 * @return	void
1734
	 */
1735
	function publishAction()	{
1736

    
1737
			// If "Publish" or "Swap" buttons are pressed:
1738
		if (t3lib_div::_POST('_publish') || t3lib_div::_POST('_swap'))	{
1739

    
1740
			if ($this->table==='pages')	{	// Making sure ->uid is a page ID!
1741
					// Initialize workspace object and request all pending versions:
1742
				$wslibObj = t3lib_div::makeInstance('wslib');
1743
				$cmd = $wslibObj->getCmdArrayForPublishWS($GLOBALS['BE_USER']->workspace, t3lib_div::_POST('_swap'),$this->uid);
1744

    
1745
					// Execute the commands:
1746
				$tce = t3lib_div::makeInstance('t3lib_TCEmain');
1747
				$tce->stripslashes_values = 0;
1748
				$tce->start(array(), $cmd);
1749
				$tce->process_cmdmap();
1750

    
1751
				t3lib_BEfunc::getSetUpdateSignal('updatePageTree');
1752

    
1753
				return $tce->errorLog;
1754
			}
1755
		}
1756
	}
1757
}
1758

    
1759

    
1760

    
1761
if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/version/cm1/index.php'])	{
1762
	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/version/cm1/index.php']);
1763
}
1764

    
1765

    
1766

    
1767

    
1768
// Make instance:
1769
$SOBE = t3lib_div::makeInstance('tx_version_cm1');
1770
$SOBE->init();
1771

    
1772

    
1773
$SOBE->main();
1774
$SOBE->printContent();
1775

    
1776
?>
(2-2/3)