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