86a34a3d2fb9b10b87b76d9465bf57588c423197
[Packages/TYPO3.CMS.git] / typo3 / alt_doc.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-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 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Main form rendering script
29 * By sending certain parameters to this script you can bring up a form
30 * which allows the user to edit the content of one or more database records.
31 *
32 * $Id$
33 * Revised for TYPO3 3.6 November/2003 by Kasper Skaarhoj
34 * XHTML compliant
35 *
36 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
37 */
38 /**
39 * [CLASS/FUNCTION INDEX of SCRIPT]
40 *
41 *
42 *
43 * 105: class SC_alt_doc
44 * 179: function preInit()
45 * 241: function doProcessData()
46 * 251: function processData()
47 * 379: function init()
48 * 473: function main()
49 * 551: function printContent()
50 *
51 * SECTION: Sub-content functions, rendering specific parts of the module content.
52 * 587: function makeEditForm()
53 * 771: function makeButtonPanel()
54 * 850: function makeDocSel()
55 * 892: function makeCmenu()
56 * 914: function compileForm($panel,$docSel,$cMenu,$editForm, $langSelector='')
57 * 982: function functionMenus()
58 * 1013: function shortCutLink()
59 * 1044: function tceformMessages()
60 *
61 * SECTION: Localization stuff
62 * 1083: function languageSwitch($table, $uid, $pid=NULL)
63 * 1179: function localizationRedirect($justLocalized)
64 * 1213: function getLanguages($id)
65 *
66 * SECTION: Other functions
67 * 1275: function fixWSversioningInEditConf($mapArray=FALSE)
68 * 1324: function getRecordForEdit($table,$theUid)
69 * 1358: function editRegularContentFromId()
70 * 1386: function compileStoreDat()
71 * 1399: function getNewIconMode($table,$key='saveDocNew')
72 * 1412: function closeDocument($code=0)
73 * 1444: function setDocument($currentDocFromHandlerMD5='',$retUrl='alt_doc_nodoc.php')
74 *
75 * TOTAL FUNCTIONS: 24
76 * (This index is automatically created/updated by the extension "extdeveval")
77 *
78 */
79
80
81 require('init.php');
82 require('template.php');
83 $LANG->includeLLFile('EXT:lang/locallang_alt_doc.xml');
84
85 t3lib_BEfunc::lockRecords();
86
87
88
89
90 /**
91 * Script Class: Drawing the editing form for editing records in TYPO3.
92 * Notice: It does NOT use tce_db.php to submit data to, rather it handles submissions itself
93 *
94 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
95 * @package TYPO3
96 * @subpackage core
97 */
98 class SC_alt_doc {
99
100 // Internal, static: GPvars:
101 var $editconf; // GPvar "edit": Is an array looking approx like [tablename][list-of-ids]=command, eg. "&edit[pages][123]=edit". See t3lib_BEfunc::editOnClick(). Value can be seen modified internally (converting NEW keyword to id, workspace/versioning etc).
102 var $columnsOnly; // Commalist of fieldnames to edit. The point is IF you specify this list, only those fields will be rendered in the form. Otherwise all (available) fields in the record is shown according to the types configuration in $TCA
103 var $defVals; // Default values for fields (array with tablenames, fields etc. as keys). Can be seen modified internally.
104 var $overrideVals; // Array of values to force being set (as hidden fields). Will be set as $this->defVals IF defVals does not exist.
105 var $returnUrl; // If set, this value will be set in $this->retUrl (which is used quite many places as the return URL). If not set, "dummy.php" will be set in $this->retUrl
106 var $closeDoc; // Close-document command. Not really sure of all options...
107 var $doSave; // Quite simply, if this variable is set, then the processing of incoming data will be performed - as if a save-button is pressed. Used in the forms as a hidden field which can be set through JavaScript if the form is somehow submitted by JavaScript).
108
109 var $data; // GPvar (for processing only) : The data array from which the data comes...
110 var $mirror; // GPvar (for processing only) : ?
111 var $cacheCmd; // GPvar (for processing only) : Clear-cache cmd.
112 var $redirect; // GPvar (for processing only) : Redirect (not used???)
113 var $returnNewPageId; // GPvar (for processing only) : Boolean: If set, then the GET var "&id=" will be added to the retUrl string so that the NEW id of something is returned to the script calling the form.
114 var $vC; // GPvar (for processing only) : Verification code, internal stuff.
115 var $uc; // GPvar : update BE_USER->uc
116
117 var $popViewId; // GPvar (module) : ID for displaying the page in the frontend (used for SAVE/VIEW operations)
118 var $popViewId_addParams; // GPvar (module) : Additional GET vars for the link, eg. "&L=xxx"
119 var $viewUrl; // GPvar (module) : Alternative URL for viewing the frontend pages.
120 var $editRegularContentFromId; // If this is pointing to a page id it will automatically load all content elements (NORMAL column/default language) from that page into the form!
121 var $recTitle; // Alternative title for the document handler.
122 var $disHelp; // Disable help... ?
123 var $noView; // If set, then no SAVE/VIEW button is printed
124 var $returnEditConf; // If set, the $this->editconf array is returned to the calling script (used by wizard_add.php for instance)
125 var $localizationMode; // GP var, localization mode for TCEforms (eg. "text")
126
127
128 // Internal, static:
129 /**
130 * document template object
131 *
132 * @var mediumDoc
133 */
134 var $doc;
135 var $template; // a static HTML template, usually in templates/alt_doc.html
136 var $content; // Content accumulation
137
138 var $retUrl; // Return URL script, processed. This contains the script (if any) that we should RETURN TO from the alt_doc.php script IF we press the close button. Thus this variable is normally passed along from the calling script so we can properly return if needed.
139 var $R_URL_parts; // Contains the parts of the REQUEST_URI (current url). By parts we mean the result of resolving REQUEST_URI (current url) by the parse_url() function. The result is an array where eg. "path" is the script path and "query" is the parameters...
140 var $R_URL_getvars; // Contains the current GET vars array; More specifically this array is the foundation for creating the R_URI internal var (which becomes the "url of this script" to which we submit the forms etc.)
141 var $R_URI; // Set to the URL of this script including variables which is needed to re-display the form. See main()
142
143 var $storeTitle; // Is loaded with the "title" of the currently "open document" - this is used in the Document Selector box. (see makeDocSel())
144 var $storeArray; // Contains an array with key/value pairs of GET parameters needed to reach the current document displayed - used in the Document Selector box. (see compileStoreDat())
145 var $storeUrl; // Contains storeArray, but imploded into a GET parameter string (see compileStoreDat())
146 var $storeUrlMd5; // Hashed value of storeURL (see compileStoreDat())
147
148 var $docDat; // Module session data
149 var $docHandler; // An array of the "open documents" - keys are md5 hashes (see $storeUrlMd5) identifying the various documents on the GET parameter list needed to open it. The values are arrays with 0,1,2 keys with information about the document (see compileStoreDat()). The docHandler variable is stored in the $docDat session data, key "0".
150
151
152 // Internal: Related to the form rendering:
153 var $elementsData; // Array of the elements to create edit forms for.
154 var $firstEl; // Pointer to the first element in $elementsData
155 var $errorC; // Counter, used to count the number of errors (when users do not have edit permissions)
156 var $newC; // Counter, used to count the number of new record forms displayed
157 var $viewId; // Is set to the pid value of the last shown record - thus indicating which page to show when clicking the SAVE/VIEW button
158 var $viewId_addParams; // Is set to additional parameters (like "&L=xxx") if the record supports it.
159 var $modTSconfig; // Module TSconfig, loaded from main() based on the page id value of viewId
160
161 /**
162 * instance of TCEforms class
163 *
164 * @var t3lib_TCEforms
165 */
166 var $tceforms;
167 var $generalPathOfForm; // Contains the root-line path of the currently edited record(s) - for display.
168
169
170 // Internal, dynamic:
171 var $dontStoreDocumentRef; // Used internally to disable the storage of the document reference (eg. new records)
172
173
174
175
176
177
178
179 /**
180 * First initialization.
181 *
182 * @return void
183 */
184 function preInit() {
185 global $BE_USER;
186
187 if (t3lib_div::_GP('justLocalized')) {
188 $this->localizationRedirect(t3lib_div::_GP('justLocalized'));
189 }
190
191 // Setting GPvars:
192 $this->editconf = t3lib_div::_GP('edit');
193 $this->defVals = t3lib_div::_GP('defVals');
194 $this->overrideVals = t3lib_div::_GP('overrideVals');
195 $this->columnsOnly = t3lib_div::_GP('columnsOnly');
196 $this->returnUrl = t3lib_div::_GP('returnUrl');
197 $this->closeDoc = t3lib_div::_GP('closeDoc');
198 $this->doSave = t3lib_div::_GP('doSave');
199 $this->returnEditConf = t3lib_div::_GP('returnEditConf');
200 $this->localizationMode = t3lib_div::_GP('localizationMode');
201 $this->uc = t3lib_div::_GP('uc');
202
203
204 // Setting override values as default if defVals does not exist.
205 if (!is_array($this->defVals) && is_array($this->overrideVals)) {
206 $this->defVals = $this->overrideVals;
207 }
208
209 // Setting return URL
210 $this->retUrl = $this->returnUrl ? $this->returnUrl : 'dummy.php';
211
212 // Fix $this->editconf if versioning applies to any of the records
213 $this->fixWSversioningInEditConf();
214
215 // Make R_URL (request url) based on input GETvars:
216 $this->R_URL_parts = parse_url(t3lib_div::getIndpEnv('REQUEST_URI'));
217 $this->R_URL_getvars = t3lib_div::_GET();
218 $this->R_URL_getvars['edit'] = $this->editconf;
219
220 // MAKE url for storing
221 $this->compileStoreDat();
222
223 // Initialize more variables.
224 $this->dontStoreDocumentRef=0;
225 $this->storeTitle='';
226
227 // Get session data for the module:
228 $this->docDat = $BE_USER->getModuleData('alt_doc.php','ses');
229 $this->docHandler = $this->docDat[0];
230
231 // If a request for closing the document has been sent, act accordingly:
232 if ($this->closeDoc>0) {
233 $this->closeDocument($this->closeDoc);
234 }
235
236 // If NO vars are sent to the script, try to read first document:
237 if (is_array($this->R_URL_getvars) && count($this->R_URL_getvars)<2 && !is_array($this->editconf)) { // Added !is_array($this->editconf) because editConf must not be set either. Anyways I can't figure out when this situation here will apply...
238 $this->setDocument($this->docDat[1]);
239 }
240 }
241
242
243 /**
244 * Detects, if a save command has been triggered.
245 *
246 * @return boolean True, then save the document (data submitted)
247 */
248 function doProcessData() {
249 $out = $this->doSave || isset($_POST['_savedok_x']) || isset($_POST['_saveandclosedok_x']) || isset($_POST['_savedokview_x']) || isset($_POST['_savedoknew_x']) || isset($_POST['_translation_savedok_x']);
250 return $out;
251 }
252
253
254 /**
255 * Do processing of data, submitting it to TCEmain.
256 *
257 * @return void
258 */
259 function processData() {
260 global $BE_USER,$TYPO3_CONF_VARS;
261
262 // GPvars specifically for processing:
263 $this->data = t3lib_div::_GP('data');
264 $this->cmd = t3lib_div::_GP('cmd');
265 $this->mirror = t3lib_div::_GP('mirror');
266 $this->cacheCmd = t3lib_div::_GP('cacheCmd');
267 $this->redirect = t3lib_div::_GP('redirect');
268 $this->returnNewPageId = t3lib_div::_GP('returnNewPageId');
269 $this->vC = t3lib_div::_GP('vC');
270
271 // See tce_db.php for relevate options here:
272 // Only options related to $this->data submission are included here.
273 $tce = t3lib_div::makeInstance('t3lib_TCEmain');
274 $tce->stripslashes_values=0;
275 if (isset($_POST['_translation_savedok_x'])) {
276 $tce->updateModeL10NdiffData = 'FORCE_FFUPD';
277 }
278
279 // Setting default values specific for the user:
280 $TCAdefaultOverride = $BE_USER->getTSConfigProp('TCAdefaults');
281 if (is_array($TCAdefaultOverride)) {
282 $tce->setDefaultsFromUserTS($TCAdefaultOverride);
283 }
284
285 // Setting internal vars:
286 if ($BE_USER->uc['neverHideAtCopy']) {
287 $tce->neverHideAtCopy = 1;
288 }
289 $tce->debug=0;
290 $tce->disableRTE = !$BE_USER->isRTE();
291
292 // Loading TCEmain with data:
293 $tce->start($this->data,$this->cmd);
294 if (is_array($this->mirror)) {
295 $tce->setMirror($this->mirror);
296 }
297
298 // If pages are being edited, we set an instruction about updating the page tree after this operation.
299 if (isset($this->data['pages'])) {
300 t3lib_BEfunc::setUpdateSignal('updatePageTree');
301 }
302
303
304 // Checking referer / executing
305 $refInfo=parse_url(t3lib_div::getIndpEnv('HTTP_REFERER'));
306 $httpHost = t3lib_div::getIndpEnv('TYPO3_HOST_ONLY');
307 if ($httpHost!=$refInfo['host'] && $this->vC!=$BE_USER->veriCode() && !$TYPO3_CONF_VARS['SYS']['doNotCheckReferer']) {
308 $tce->log('',0,0,0,1,"Referer host '%s' and server host '%s' did not match and veriCode was not valid either!",1,array($refInfo['host'],$httpHost));
309 debug('Error: Referer host did not match with server host.');
310 } else {
311
312 // Perform the saving operation with TCEmain:
313 $tce->process_uploads($_FILES);
314 $tce->process_datamap();
315 $tce->process_cmdmap();
316
317 // If there was saved any new items, load them:
318 if (count($tce->substNEWwithIDs_table)) {
319 // save the expanded/collapsed states for new inline records, if any
320 t3lib_TCEforms_inline::updateInlineView($this->uc, $tce);
321
322 $newEditConf = array();
323
324 foreach($this->editconf as $tableName => $tableCmds) {
325 $keys = array_keys($tce->substNEWwithIDs_table, $tableName);
326 if(count($keys) > 0) {
327 foreach($keys as $key) {
328 $editId = $tce->substNEWwithIDs[$key];
329 // check if the $editId isn't a child record of an IRRE action
330 if (!(is_array($tce->newRelatedIDs[$tableName]) && in_array($editId, $tce->newRelatedIDs[$tableName]))) {
331 // translate new id to the workspace version:
332 if ($versionRec = t3lib_BEfunc::getWorkspaceVersionOfRecord($GLOBALS['BE_USER']->workspace, $tableName, $editId,'uid')) {
333 $editId = $versionRec['uid'];
334 }
335 $newEditConf[$tableName][$editId] = 'edit';
336 }
337
338 // Traverse all new records and forge the content of ->editconf so we can continue to EDIT these records!
339 if ($tableName=='pages' && $this->retUrl!='dummy.php' && $this->returnNewPageId) {
340 $this->retUrl.='&id='.$tce->substNEWwithIDs[$key];
341 }
342 }
343 } else {
344 $newEditConf[$tableName] = $tableCmds;
345 }
346 }
347
348 // Resetting editconf if newEditConf has values:
349 if (count($newEditConf)) {
350 $this->editconf = $newEditConf;
351 }
352
353 // Finally, set the editconf array in the "getvars" so they will be passed along in URLs as needed.
354 $this->R_URL_getvars['edit']=$this->editconf;
355
356 // Unsetting default values since we don't need them anymore.
357 unset($this->R_URL_getvars['defVals']);
358
359 // Re-compile the store* values since editconf changed...
360 $this->compileStoreDat();
361 }
362
363 // See if any records was auto-created as new versions?
364 if (count($tce->autoVersionIdMap)) {
365 $this->fixWSversioningInEditConf($tce->autoVersionIdMap);
366 }
367
368 // If a document is saved and a new one is created right after.
369 if (isset($_POST['_savedoknew_x']) && is_array($this->editconf)) {
370
371 // Finding the current table:
372 reset($this->editconf);
373 $nTable=key($this->editconf);
374
375 // Finding the first id, getting the records pid+uid
376 reset($this->editconf[$nTable]);
377 $nUid=key($this->editconf[$nTable]);
378 $nRec = t3lib_BEfunc::getRecord($nTable,$nUid,'pid,uid');
379
380 // Setting a blank editconf array for a new record:
381 $this->editconf=array();
382 if ($this->getNewIconMode($nTable)=='top') {
383 $this->editconf[$nTable][$nRec['pid']]='new';
384 } else {
385 $this->editconf[$nTable][-$nRec['uid']]='new';
386 }
387
388 // Finally, set the editconf array in the "getvars" so they will be passed along in URLs as needed.
389 $this->R_URL_getvars['edit']=$this->editconf;
390
391 // Re-compile the store* values since editconf changed...
392 $this->compileStoreDat();
393 }
394
395 $tce->printLogErrorMessages(
396 (isset($_POST['_saveandclosedok_x']) || isset($_POST['_translation_savedok_x'])) ?
397 $this->retUrl :
398 $this->R_URL_parts['path'].'?'.t3lib_div::implodeArrayForUrl('',$this->R_URL_getvars) // popView will not be invoked here, because the information from the submit button for save/view will be lost .... But does it matter if there is an error anyways?
399 );
400 }
401 if ((isset($_POST['_saveandclosedok_x']) || isset($_POST['_translation_savedok_x'])) || $this->closeDoc<0) { // || count($tce->substNEWwithIDs)... If any new items has been save, the document is CLOSED because if not, we just get that element re-listed as new. And we don't want that!
402 $this->closeDocument(abs($this->closeDoc));
403 }
404 }
405
406 /**
407 * Initialize the normal module operation
408 *
409 * @return void
410 */
411 function init() {
412 global $BE_USER,$LANG,$BACK_PATH;
413
414 // Setting more GPvars:
415 $this->popViewId = t3lib_div::_GP('popViewId');
416 $this->popViewId_addParams = t3lib_div::_GP('popViewId_addParams');
417 $this->viewUrl = t3lib_div::_GP('viewUrl');
418 $this->editRegularContentFromId = t3lib_div::_GP('editRegularContentFromId');
419 $this->recTitle = t3lib_div::_GP('recTitle');
420 $this->disHelp = t3lib_div::_GP('disHelp');
421 $this->noView = t3lib_div::_GP('noView');
422
423 $this->perms_clause = $BE_USER->getPagePermsClause(1);
424
425 // Set other internal variables:
426 $this->R_URL_getvars['returnUrl']=$this->retUrl;
427 $this->R_URI = $this->R_URL_parts['path'].'?'.t3lib_div::implodeArrayForUrl('',$this->R_URL_getvars);
428
429 // MENU-ITEMS:
430 // If array, then it's a selector box menu
431 // If empty string it's just a variable, that'll be saved.
432 // Values NOT in this array will not be saved in the settings-array for the module.
433 $this->MOD_MENU = array(
434 'showPalettes' => ''
435 );
436
437 // Setting virtual document name
438 $this->MCONF['name']='xMOD_alt_doc.php';
439
440 // CLEANSE SETTINGS
441 $this->MOD_SETTINGS = t3lib_BEfunc::getModuleData($this->MOD_MENU, t3lib_div::_GP('SET'), $this->MCONF['name']);
442
443 // Create an instance of the document template object
444 $this->doc = $GLOBALS['TBE_TEMPLATE'];
445 $this->doc->backPath = $BACK_PATH;
446 $this->doc->setModuleTemplate('templates/alt_doc.html');
447 $this->doc->form = '<form action="'.htmlspecialchars($this->R_URI).'" method="post" enctype="'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['form_enctype'].'" name="editform" onsubmit="document.editform._scrollPosition.value=(document.documentElement.scrollTop || document.body.scrollTop); return TBE_EDITOR.checkSubmit(1);">';
448
449 $this->doc->loadPrototype();
450 $this->doc->JScode = $this->doc->wrapScriptTags('
451 function jumpToUrl(URL,formEl) { //
452 if (!TBE_EDITOR.isFormChanged()) {
453 window.location.href = URL;
454 } else if (formEl && formEl.type=="checkbox") {
455 formEl.checked = formEl.checked ? 0 : 1;
456 }
457 }
458 // Object: TS:
459 function typoSetup () { //
460 this.uniqueID = "";
461 }
462 var TS = new typoSetup();
463
464 // Info view:
465 function launchView(table,uid,bP) { //
466 var backPath= bP ? bP : "";
467 var thePreviewWindow="";
468 thePreviewWindow = window.open(backPath+"show_item.php?table="+encodeURIComponent(table)+"&uid="+encodeURIComponent(uid),"ShowItem"+TS.uniqueID,"height=300,width=410,status=0,menubar=0,resizable=0,location=0,directories=0,scrollbars=1,toolbar=0");
469 if (thePreviewWindow && thePreviewWindow.focus) {
470 thePreviewWindow.focus();
471 }
472 }
473 function deleteRecord(table,id,url) { //
474 if (
475 '.($GLOBALS['BE_USER']->jsConfirmation(4)?'confirm('.$LANG->JScharCode($LANG->getLL('deleteWarning')).')':'1==1').'
476 ) {
477 window.location.href = "tce_db.php?cmd["+table+"]["+id+"][delete]=1&redirect="+escape(url)+"&vC='.$BE_USER->veriCode().'&prErr=1&uPT=1";
478 }
479 return false;
480 }
481 '.(isset($_POST['_savedokview_x']) && $this->popViewId ?
482 'if (window.opener) { '.
483 t3lib_BEfunc::viewOnClick($this->popViewId,'',t3lib_BEfunc::BEgetRootLine($this->popViewId),'',$this->viewUrl,$this->popViewId_addParams,FALSE).
484 ' } else { '.
485 t3lib_BEfunc::viewOnClick($this->popViewId,'',t3lib_BEfunc::BEgetRootLine($this->popViewId),'',$this->viewUrl,$this->popViewId_addParams).
486 ' } '
487 : '')
488 ).$this->doc->getDynTabMenuJScode();
489
490 // Setting up the context sensitive menu:
491 $this->doc->getContextMenuCode();
492 $this->doc->bodyTagAdditions = 'onload="window.scrollTo(0,'.t3lib_div::intInRange(t3lib_div::_GP('_scrollPosition'),0,10000).');"';
493 }
494
495 /**
496 * Main module operation
497 *
498 * @return void
499 */
500 function main() {
501 global $BE_USER,$LANG;
502
503 // Begin edit:
504 if (is_array($this->editconf)) {
505
506 // Initialize TCEforms (rendering the forms)
507 $this->tceforms = t3lib_div::makeInstance('t3lib_TCEforms');
508 $this->tceforms->initDefaultBEMode();
509 $this->tceforms->doSaveFieldName = 'doSave';
510 $this->tceforms->localizationMode = t3lib_div::inList('text,media',$this->localizationMode) ? $this->localizationMode : ''; // text,media is keywords defined in TYPO3 Core API..., see "l10n_cat"
511 $this->tceforms->returnUrl = $this->R_URI;
512 $this->tceforms->palettesCollapsed = !$this->MOD_SETTINGS['showPalettes'];
513 $this->tceforms->disableRTE = !$BE_USER->isRTE();
514 $this->tceforms->enableClickMenu = TRUE;
515 $this->tceforms->enableTabMenu = TRUE;
516
517 // Clipboard is initialized:
518 $this->tceforms->clipObj = t3lib_div::makeInstance('t3lib_clipboard'); // Start clipboard
519 $this->tceforms->clipObj->initializeClipboard(); // Initialize - reads the clipboard content from the user session
520
521 // Setting external variables:
522 $this->tceforms->edit_showFieldHelp = $BE_USER->uc['edit_showFieldHelp'];
523
524 if ($this->editRegularContentFromId) {
525 $this->editRegularContentFromId();
526 }
527
528
529 // Creating the editing form, wrap it with buttons, document selector etc.
530 $editForm = $this->makeEditForm();
531
532 if ($editForm) {
533 $this->firstEl = reset($this->elementsData);
534
535 // Checking if the currently open document is stored in the list of "open documents" - if not, then add it:
536 if ((strcmp($this->docDat[1], $this->storeUrlMd5) || !isset($this->docHandler[$this->storeUrlMd5])) && !$this->dontStoreDocumentRef) {
537 $this->docHandler[$this->storeUrlMd5] = array($this->storeTitle, $this->storeArray, $this->storeUrl, $this->firstEl);
538 $BE_USER->pushModuleData('alt_doc.php', array($this->docHandler, $this->storeUrlMd5));
539 t3lib_BEfunc::setUpdateSignal('tx_opendocs::updateNumber', count($this->docHandler));
540 }
541
542
543 // Module configuration
544 $this->modTSconfig = ($this->viewId ? t3lib_BEfunc::getModTSconfig($this->viewId,'mod.xMOD_alt_doc') : array());
545
546 $body.= $this->tceforms->printNeededJSFunctions_top();
547 $body.= $this->compileForm($editForm);
548 $body.= $this->tceforms->printNeededJSFunctions();
549 $body.= $this->functionMenus();
550 $body.= $this->tceformMessages();
551 }
552 }
553
554 // Access check...
555 // The page will show only if there is a valid page and if this page may be viewed by the user
556 $this->pageinfo = t3lib_BEfunc::readPageAccess($this->viewId, $this->perms_clause);
557
558 // Setting up the buttons and markers for docheader
559 $docHeaderButtons = $this->getButtons();
560 $markers = array(
561 'LANGSELECTOR' => $this->langSelector(),
562 'EXTRAHEADER' => $this->extraFormHeaders(),
563 'CSH' => $docHeaderButtons['csh'],
564 'CONTENT' => $body
565 );
566
567 // Build the <body> for the module
568 $this->content = $this->doc->startPage('TYPO3 Edit Document');
569 $this->content.= $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
570 $this->content.= $this->doc->endPage();
571 $this->content = $this->doc->insertStylesAndJS($this->content);
572 }
573
574
575 /**
576 * Outputting the accumulated content to screen
577 *
578 * @return void
579 */
580 function printContent() {
581 echo $this->content;
582 }
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603 /***************************
604 *
605 * Sub-content functions, rendering specific parts of the module content.
606 *
607 ***************************/
608
609 /**
610 * Creates the editing form with TCEforms, based on the input from GPvars.
611 *
612 * @return string HTML form elements wrapped in tables
613 */
614 function makeEditForm() {
615 global $BE_USER,$LANG,$TCA;
616
617 // Initialize variables:
618 $this->elementsData=array();
619 $this->errorC=0;
620 $this->newC=0;
621 $thePrevUid='';
622 $editForm='';
623
624 // Traverse the GPvar edit array
625 foreach($this->editconf as $table => $conf) { // Tables:
626 if (is_array($conf) && $TCA[$table] && $BE_USER->check('tables_modify',$table)) {
627
628 // Traverse the keys/comments of each table (keys can be a commalist of uids)
629 foreach($conf as $cKey => $cmd) {
630 if ($cmd=='edit' || $cmd=='new') {
631
632 // Get the ids:
633 $ids = t3lib_div::trimExplode(',',$cKey,1);
634
635 // Traverse the ids:
636 foreach($ids as $theUid) {
637
638 // Checking if the user has permissions? (Only working as a precaution, because the final permission check is always down in TCE. But it's good to notify the user on beforehand...)
639 // First, resetting flags.
640 $hasAccess = 1;
641 $deniedAccessReason = '';
642 $deleteAccess = 0;
643 $this->viewId = 0;
644
645 // If the command is to create a NEW record...:
646 if ($cmd=='new') {
647 if (intval($theUid)) { // NOTICE: the id values in this case points to the page uid onto which the record should be create OR (if the id is negativ) to a record from the same table AFTER which to create the record.
648
649 // Find parent page on which the new record reside
650 if ($theUid<0) { // Less than zero - find parent page
651 $calcPRec=t3lib_BEfunc::getRecord($table,abs($theUid));
652 $calcPRec=t3lib_BEfunc::getRecord('pages',$calcPRec['pid']);
653 } else { // always a page
654 $calcPRec=t3lib_BEfunc::getRecord('pages',abs($theUid));
655 }
656
657 // Now, calculate whether the user has access to creating new records on this position:
658 if (is_array($calcPRec)) {
659 $CALC_PERMS = $BE_USER->calcPerms($calcPRec); // Permissions for the parent page
660 if ($table=='pages') { // If pages:
661 $hasAccess = $CALC_PERMS&8 ? 1 : 0;
662 $this->viewId = $calcPRec['pid'];
663 } else {
664 $hasAccess = $CALC_PERMS&16 ? 1 : 0;
665 $this->viewId = $calcPRec['uid'];
666 }
667 }
668 }
669 $this->dontStoreDocumentRef=1; // Don't save this document title in the document selector if the document is new.
670 } else { // Edit:
671 $calcPRec = t3lib_BEfunc::getRecord($table,$theUid);
672 t3lib_BEfunc::fixVersioningPid($table,$calcPRec);
673 if (is_array($calcPRec)) {
674 if ($table=='pages') { // If pages:
675 $CALC_PERMS = $BE_USER->calcPerms($calcPRec);
676 $hasAccess = $CALC_PERMS&2 ? 1 : 0;
677 $deleteAccess = $CALC_PERMS&4 ? 1 : 0;
678 $this->viewId = $calcPRec['uid'];
679 } else {
680 $CALC_PERMS = $BE_USER->calcPerms(t3lib_BEfunc::getRecord('pages',$calcPRec['pid'])); // Fetching pid-record first.
681 $hasAccess = $CALC_PERMS&16 ? 1 : 0;
682 $deleteAccess = $CALC_PERMS&16 ? 1 : 0;
683 $this->viewId = $calcPRec['pid'];
684
685 // Adding "&L=xx" if the record being edited has a languageField with a value larger than zero!
686 if ($TCA[$table]['ctrl']['languageField'] && $calcPRec[$TCA[$table]['ctrl']['languageField']]>0) {
687 $this->viewId_addParams = '&L='.$calcPRec[$TCA[$table]['ctrl']['languageField']];
688 }
689 }
690
691 // Check internals regarding access:
692 if ($hasAccess) {
693 $hasAccess = $BE_USER->recordEditAccessInternals($table, $calcPRec);
694 $deniedAccessReason = $BE_USER->errorMsg;
695 }
696 } else $hasAccess = 0;
697 }
698
699 // AT THIS POINT we have checked the access status of the editing/creation of records and we can now proceed with creating the form elements:
700
701 if ($hasAccess) {
702 $prevPageID = is_object($trData)?$trData->prevPageID:'';
703 $trData = t3lib_div::makeInstance('t3lib_transferData');
704 $trData->addRawData = TRUE;
705 $trData->defVals = $this->defVals;
706 $trData->lockRecords=1;
707 $trData->disableRTE = !$BE_USER->isRTE();
708 $trData->prevPageID = $prevPageID;
709 $trData->fetchRecord($table,$theUid,$cmd=='new'?'new':''); // 'new'
710 reset($trData->regTableItems_data);
711 $rec = current($trData->regTableItems_data);
712 $rec['uid'] = $cmd=='new' ? uniqid('NEW') : $theUid;
713 if ($cmd=='new') {
714 $rec['pid'] = $theUid=='prev'?$thePrevUid:$theUid;
715 }
716 $this->elementsData[]=array(
717 'table' => $table,
718 'uid' => $rec['uid'],
719 'pid' => $rec['pid'],
720 'cmd' => $cmd,
721 'deleteAccess' => $deleteAccess
722 );
723
724 // Now, render the form:
725 if (is_array($rec)) {
726
727 // Setting visual path / title of form:
728 $this->generalPathOfForm = $this->tceforms->getRecordPath($table,$rec);
729 if (!$this->storeTitle) {
730 $this->storeTitle = $this->recTitle ? htmlspecialchars($this->recTitle) : t3lib_BEfunc::getRecordTitle($table,$rec,TRUE);
731 }
732
733 // Setting variables in TCEforms object:
734 $this->tceforms->hiddenFieldList = '';
735 $this->tceforms->globalShowHelp = $this->disHelp ? 0 : 1;
736 if (is_array($this->overrideVals[$table])) {
737 $this->tceforms->hiddenFieldListArr = array_keys($this->overrideVals[$table]);
738 }
739
740 // Register default language labels, if any:
741 $this->tceforms->registerDefaultLanguageData($table,$rec);
742
743 // Create form for the record (either specific list of fields or the whole record):
744 $panel = '';
745 if ($this->columnsOnly) {
746 if(is_array($this->columnsOnly)){
747 $panel.= $this->tceforms->getListedFields($table,$rec,$this->columnsOnly[$table]);
748 } else {
749 $panel.= $this->tceforms->getListedFields($table,$rec,$this->columnsOnly);
750 }
751 } else {
752 $panel.= $this->tceforms->getMainFields($table,$rec);
753 }
754 $panel = $this->tceforms->wrapTotal($panel,$rec,$table);
755
756 // Setting the pid value for new records:
757 if ($cmd=='new') {
758 $panel.= '<input type="hidden" name="data['.$table.']['.$rec['uid'].'][pid]" value="'.$rec['pid'].'" />';
759 $this->newC++;
760 }
761
762 // Display "is-locked" message:
763 if ($lockInfo = t3lib_BEfunc::isRecordLocked($table,$rec['uid'])) {
764 $lockIcon = '
765
766 <!-- Warning box: -->
767 <table border="0" cellpadding="0" cellspacing="0" class="warningbox">
768 <tr>
769 <td><img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/recordlock_warning3.gif','width="17" height="12"').' alt="" /></td>
770 <td>'.htmlspecialchars($lockInfo['msg']).'</td>
771 </tr>
772 </table>
773 ';
774 } else $lockIcon = '';
775
776 // Combine it all:
777 $editForm.= $lockIcon.$panel;
778 }
779
780 $thePrevUid = $rec['uid'];
781 } else {
782 $this->errorC++;
783 $editForm.=$LANG->sL('LLL:EXT:lang/locallang_core.php:labels.noEditPermission',1).'<br /><br />'.
784 ($deniedAccessReason ? 'Reason: ' . htmlspecialchars($deniedAccessReason) . '<br /><br />' : '');
785 }
786 }
787 }
788 }
789 }
790 }
791
792 return $editForm;
793 }
794
795 /**
796 * Create the panel of buttons for submitting the form or otherwise perform operations.
797 *
798 * @return array all available buttons as an assoc. array
799 */
800 protected function getButtons() {
801 global $TCA,$LANG;
802 $buttons = array(
803 'save' => '',
804 'save_view' => '',
805 'save_new' => '',
806 'save_close' => '',
807 'close' => '',
808 'delete' => '',
809 'undo' => '',
810 'history' => '',
811 'columns_only' => '',
812 'csh' => '',
813 'translation_save' => ''
814 );
815
816 // Render SAVE type buttons:
817 // The action of each button is decided by its name attribute. (See doProcessData())
818 if (!$this->errorC && !$TCA[$this->firstEl['table']]['ctrl']['readOnly']) {
819
820 // SAVE button:
821 $buttons['save'] = '<input type="image" class="c-inputButton" name="_savedok" src="' . t3lib_iconWorks::skinImg($this->doc->backPath, 'gfx/savedok.gif', '', 1) . '" title="' . $LANG->sL('LLL:EXT:lang/locallang_core.php:rm.saveDoc', 1) . '" />';
822
823 // SAVE / VIEW button:
824 if ($this->viewId && !$this->noView && t3lib_extMgm::isLoaded('cms') && $this->getNewIconMode($this->firstEl['table'], 'saveDocView')) {
825 $buttons['save_view'] = '<input type="image" class="c-inputButton" name="_savedokview" src="' . t3lib_iconWorks::skinImg($this->doc->backPath, 'gfx/savedokshow.gif', '', 1) . '" title="' . $LANG->sL('LLL:EXT:lang/locallang_core.php:rm.saveDocShow', 1) . '" />';
826 }
827
828 // SAVE / NEW button:
829 if (count($this->elementsData)==1 && $this->getNewIconMode($this->firstEl['table'])) {
830 $buttons['save_new'] = '<input type="image" class="c-inputButton" name="_savedoknew" src="' . t3lib_iconWorks::skinImg($this->doc->backPath, 'gfx/savedoknew.gif', '', 1) . '" title="' . $LANG->sL('LLL:EXT:lang/locallang_core.php:rm.saveNewDoc', 1) . '" />';
831 }
832
833 // SAVE / CLOSE
834 $buttons['save_close'] = '<input type="image" class="c-inputButton" name="_saveandclosedok" src="' . t3lib_iconWorks::skinImg($this->doc->backPath, 'gfx/saveandclosedok.gif', '', 1) . '" title="' . $LANG->sL('LLL:EXT:lang/locallang_core.php:rm.saveCloseDoc', 1) . '" />';
835
836 // FINISH TRANSLATION / SAVE / CLOSE
837 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['explicitConfirmationOfTranslation']) {
838 $buttons['translation_save'] = '<input type="image" class="c-inputButton" name="_translation_savedok" src="' . t3lib_iconWorks::skinImg($this->doc->backPath, 'gfx/translationsavedok.gif', '', 1) . '" title="' . $LANG->sL('LLL:EXT:lang/locallang_core.php:rm.translationSaveDoc', 1) . '" />';
839 }
840 }
841
842 // CLOSE button:
843 $buttons['close'] = '<a href="#" onclick="document.editform.closeDoc.value=1; document.editform.submit(); return false;">'.
844 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/closedok.gif','width="21" height="16"').' class="c-inputButton" title="'.$LANG->sL('LLL:EXT:lang/locallang_core.php:rm.closeDoc',1).'" alt="" />'.
845 '</a>';
846
847
848 // DELETE + UNDO buttons:
849 if (!$this->errorC && !$TCA[$this->firstEl['table']]['ctrl']['readOnly'] && count($this->elementsData)==1) {
850 if ($this->firstEl['cmd']!='new' && t3lib_div::testInt($this->firstEl['uid'])) {
851
852 // Delete:
853 if ($this->firstEl['deleteAccess'] && !$TCA[$this->firstEl['table']]['ctrl']['readOnly'] && !$this->getNewIconMode($this->firstEl['table'],'disableDelete')) {
854 $aOnClick = 'return deleteRecord(\''.$this->firstEl['table'].'\',\''.$this->firstEl['uid'].'\',unescape(\''.rawurlencode($this->retUrl).'\'));';
855 $buttons['delete'] = '<a href="#" onclick="'.htmlspecialchars($aOnClick).'">'.
856 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/deletedok.gif','width="21" height="16"').' class="c-inputButton" title="'.$LANG->getLL('deleteItem',1).'" alt="" />'.
857 '</a>';
858 }
859
860 // Undo:
861 $undoRes = $GLOBALS['TYPO3_DB']->exec_SELECTquery('tstamp', 'sys_history', 'tablename='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->firstEl['table'], 'sys_history').' AND recuid='.intval($this->firstEl['uid']), '', 'tstamp DESC', '1');
862 if ($undoButtonR = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($undoRes)) {
863 $aOnClick = 'window.location.href=\'show_rechis.php?element='.rawurlencode($this->firstEl['table'].':'.$this->firstEl['uid']).'&revert=ALL_FIELDS&sumUp=-1&returnUrl='.rawurlencode($this->R_URI).'\'; return false;';
864 $buttons['undo'] = '<a href="#" onclick="'.htmlspecialchars($aOnClick).'">'.
865 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/undo.gif','width="21" height="16"').' class="c-inputButton" title="'.htmlspecialchars(sprintf($LANG->getLL('undoLastChange'),t3lib_BEfunc::calcAge(time()-$undoButtonR['tstamp'],$LANG->sL('LLL:EXT:lang/locallang_core.php:labels.minutesHoursDaysYears')))).'" alt="" />'.
866 '</a>';
867 }
868 if ($this->getNewIconMode($this->firstEl['table'],'showHistory')) {
869 $aOnClick = 'window.location.href=\'show_rechis.php?element='.rawurlencode($this->firstEl['table'].':'.$this->firstEl['uid']).'&returnUrl='.rawurlencode($this->R_URI).'\'; return false;';
870 $buttons['history'] = '<a href="#" onclick="'.htmlspecialchars($aOnClick).'">'.
871 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/history2.gif','width="13" height="12"').' class="c-inputButton" alt="" />'.
872 '</a>';
873 }
874
875 // If only SOME fields are shown in the form, this will link the user to the FULL form:
876 if ($this->columnsOnly) {
877 $buttons['columns_only'] = '<a href="'.htmlspecialchars($this->R_URI.'&columnsOnly=').'">'.
878 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/edit2.gif','width="11" height="12"').' class="c-inputButton" title="'.$LANG->getLL('editWholeRecord',1).'" alt="" />'.
879 '</a>';
880 }
881 }
882 }
883
884 // add the CSH icon
885 $buttons['csh'] = t3lib_BEfunc::cshItem('xMOD_csh_corebe', 'TCEforms', $GLOBALS['BACK_PATH'], '', TRUE);
886 $buttons['shortcut'] = $this->shortCutLink();
887 $buttons['open_in_new_window'] = $this->openInNewWindowLink();
888 return $buttons;
889 }
890
891 /**
892 * Returns the language switch/selector for editing,
893 * show only when a single record is edited
894 * - multiple records are too confusing
895 * @return string the HTML
896 */
897 function langSelector() {
898 $langSelector = '';
899 if (count($this->elementsData) == 1) {
900 $langSelector = $this->languageSwitch($this->firstEl['table'], $this->firstEl['uid'], $this->firstEl['pid']);
901 }
902 return $langSelector;
903 }
904
905
906 /**
907 * Compiles the extra form headers if the tceforms
908 *
909 * @return string the HTML
910 */
911 function extraFormHeaders() {
912 $extraTemplate = '';
913
914 if (is_array($this->tceforms->extraFormHeaders)) {
915 $extraTemplate = t3lib_parsehtml::getSubpart($this->doc->moduleTemplate, '###DOCHEADER_EXTRAHEADER###');
916 $extraTemplate = t3lib_parsehtml::substituteMarker($extraTemplate, '###EXTRAHEADER###', implode(chr(10), $this->tceforms->extraFormHeaders));
917 }
918 return $extraTemplate;
919 }
920
921
922 /**
923 * Put together the various elements (buttons, selectors, form) into a table
924 *
925 * @param string HTML form.
926 * @return string Composite HTML
927 */
928 function compileForm($editForm) {
929 global $LANG;
930
931 $formContent = '
932 <!-- EDITING FORM -->
933 '.$editForm.'
934
935 <input type="hidden" name="returnUrl" value="'.htmlspecialchars($this->retUrl).'" />
936 <input type="hidden" name="viewUrl" value="'.htmlspecialchars($this->viewUrl).'" />';
937
938 if ($this->returnNewPageId) {
939 $formContent .= '<input type="hidden" name="returnNewPageId" value="1" />';
940 }
941 $formContent .= '<input type="hidden" name="popViewId" value="'.htmlspecialchars($this->viewId).'" />';
942 if ($this->viewId_addParams) {
943 $formContent .= '<input type="hidden" name="popViewId_addParams" value="'.htmlspecialchars($this->viewId_addParams).'" />';
944 }
945 $formContent .= '
946 <input type="hidden" name="closeDoc" value="0" />
947 <input type="hidden" name="doSave" value="0" />
948 <input type="hidden" name="_serialNumber" value="'.md5(microtime()).'" />
949 <input type="hidden" name="_scrollPosition" value="" />';
950
951 return $formContent;
952 }
953
954 /**
955 * Create the checkbox buttons in the bottom of the pages.
956 *
957 * @return string HTML for function menus.
958 */
959 function functionMenus() {
960 global $LANG;
961
962 // Show palettes:
963 return '
964 <!-- Function menus (checkboxes for selecting options): -->
965 <br />'.t3lib_BEfunc::getFuncCheck('','SET[showPalettes]',$this->MOD_SETTINGS['showPalettes'],'alt_doc.php',t3lib_div::implodeArrayForUrl('',array_merge($this->R_URL_getvars,array('SET'=>''))),'id="checkShowPalettes"').'<label for="checkShowPalettes">'.$LANG->sL('LLL:EXT:lang/locallang_core.php:labels.showPalettes',1).'</label>';
966 }
967
968
969 /**
970 * Create shortcut icon
971 *
972 * @return string
973 */
974 function shortCutLink() {
975 global $BE_USER,$LANG;
976
977 if ($this->returnUrl == 'close.html' || !$BE_USER->mayMakeShortcut()) {
978 return '';
979 }
980 return $this->doc->makeShortcutIcon('returnUrl,edit,defVals,overrideVals,columnsOnly,returnNewPageId,editRegularContentFromId,disHelp,noView',implode(',',array_keys($this->MOD_MENU)),$this->MCONF['name'],1);
981 }
982
983
984 /**
985 * Creates open-in-window link
986 *
987 * @return string
988 */
989 function openInNewWindowLink() {
990 global $BE_USER, $LANG;
991 if ($this->returnUrl == 'close.html') {
992 return '';
993 }
994 $aOnClick = 'vHWin=window.open(\''.t3lib_div::linkThisScript(array('returnUrl'=>'close.html')).'\',\''.md5($this->R_URI).'\',\'width=670,height=500,status=0,menubar=0,scrollbars=1,resizable=1\');vHWin.focus();return false;';
995 return '<a href="#" onclick="'.htmlspecialchars($aOnClick).'">'.
996 '<img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/open_in_new_window.gif','width="19" height="14"').' title="'.$LANG->sL('LLL:EXT:lang/locallang_core.php:labels.openInNewWindow',1).'" alt="" /></a>';
997 }
998
999
1000 /**
1001 * Reads comment messages from TCEforms and prints them in a HTML comment in the bottom of the page.
1002 *
1003 * @return void
1004 */
1005 function tceformMessages() {
1006 if (count($this->tceforms->commentMessages)) {
1007 $tceformMessages = '
1008 <!-- TCEFORM messages
1009 '.htmlspecialchars(implode(chr(10),$this->tceforms->commentMessages)).'
1010 -->
1011 ';
1012 }
1013 return $tceformMessages;
1014 }
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028 /***************************
1029 *
1030 * Localization stuff
1031 *
1032 ***************************/
1033
1034 /**
1035 * Make selector box for creating new translation for a record or switching to edit the record in an existing language.
1036 * Displays only languages which are available for the current page.
1037 *
1038 * @param string Table name
1039 * @param integer uid for which to create a new language
1040 * @param integer pid of the record
1041 * @return string <select> HTML element (if there were items for the box anyways...)
1042 */
1043 function languageSwitch($table, $uid, $pid=NULL) {
1044 global $TCA;
1045
1046 $content = '';
1047
1048 $languageField = $TCA[$table]['ctrl']['languageField'];
1049 $transOrigPointerField = $TCA[$table]['ctrl']['transOrigPointerField'];
1050
1051 // table editable and activated for languages?
1052 if ($GLOBALS['BE_USER']->check('tables_modify',$table) && $languageField && $transOrigPointerField && !$TCA[$table]['ctrl']['transOrigPointerTable']) {
1053
1054 if(is_null($pid)) {
1055 $row = t3lib_befunc::getRecord($table, $uid, 'pid');
1056 $pid = $row['pid'];
1057 }
1058
1059 // get all avalibale languages for the page
1060 $langRows = $this->getLanguages($pid);
1061
1062 // page available in other languages than default language?
1063 if (is_array($langRows) && count($langRows)>1) {
1064
1065 $rowsByLang = array();
1066 $fetchFields = 'uid,'.$languageField.','.$transOrigPointerField;
1067
1068 // get record in current language
1069 $rowCurrent = t3lib_befunc::getRecord($table, $uid, $fetchFields);
1070 $currentLanguage = $rowCurrent[$languageField];
1071
1072 if ($currentLanguage>-1) { // Disabled for records with [all] language!
1073 // get record in default language if needed
1074 if ($currentLanguage) {
1075 $rowsByLang[0] = t3lib_befunc::getRecord($table, $rowCurrent[$transOrigPointerField], $fetchFields);
1076 } else {
1077 $rowsByLang[0] = $rowCurrent;
1078 }
1079
1080 // get record in other languages to see what's already available
1081 $translations = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
1082 $fetchFields,
1083 $table,
1084 'pid='.intval($pid).
1085 ' AND '.$languageField.'>0'.
1086 ' AND '.$transOrigPointerField.'='.intval($rowsByLang[0]['uid']).
1087 t3lib_BEfunc::deleteClause($table).
1088 t3lib_BEfunc::versioningPlaceholderClause($table)
1089 );
1090 foreach ($translations as $row) {
1091 $rowsByLang[$row[$languageField]] = $row;
1092 }
1093
1094 $langSelItems=array();
1095 foreach ($langRows as $lang) {
1096 if ($GLOBALS['BE_USER']->checkLanguageAccess($lang['uid'])) {
1097
1098 $newTranslation = isset($rowsByLang[$lang['uid']]) ? '' : ' ['.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:labels.new',1).']';
1099
1100 // create url for creating a localized record
1101 if($newTranslation) {
1102 $href = $this->doc->issueCommand(
1103 '&cmd['.$table.']['.$rowsByLang[0]['uid'].'][localize]='.$lang['uid'],
1104 $this->backPath.'alt_doc.php?justLocalized='.rawurlencode($table.':'.$rowsByLang[0]['uid'].':'.$lang['uid']).'&returnUrl='.rawurlencode($this->retUrl)
1105 );
1106
1107 // create edit url
1108 } else {
1109 $href = $this->backPath.'alt_doc.php?';
1110 $href .= '&edit['.$table.']['.$rowsByLang[$lang['uid']]['uid'].']=edit';
1111 $href .= '&returnUrl='.rawurlencode($this->retUrl);
1112 }
1113
1114 $langSelItems[$lang['uid']]='
1115 <option value="'.htmlspecialchars($href).'"'.($currentLanguage==$lang['uid']?' selected="selected"':'').'>'.htmlspecialchars($lang['title'].$newTranslation).'</option>';
1116 }
1117 }
1118
1119 // If any languages are left, make selector:
1120 if (count($langSelItems)>1) {
1121 $onChange = 'if(this.options[this.selectedIndex].value){window.location.href=(this.options[this.selectedIndex].value);}';
1122 $content = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_general.xml:LGL.language',1).' <select name="_langSelector" onchange="'.htmlspecialchars($onChange).'">
1123 '.implode('',$langSelItems).'
1124 </select>';
1125 }
1126 }
1127 }
1128 }
1129 return $content;
1130 }
1131
1132
1133 /**
1134 * Redirects to alt_doc with new parameters to edit a just created localized record
1135 *
1136 * @param string String passed by GET &justLocalized=
1137 * @return void
1138 */
1139 function localizationRedirect($justLocalized) {
1140 global $TCA;
1141
1142 list($table,$orig_uid,$language) = explode(':',$justLocalized);
1143
1144 if ($TCA[$table] && $TCA[$table]['ctrl']['languageField'] && $TCA[$table]['ctrl']['transOrigPointerField']) {
1145 list($localizedRecord) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
1146 'uid',
1147 $table,
1148 $TCA[$table]['ctrl']['languageField'].'='.intval($language).' AND '.
1149 $TCA[$table]['ctrl']['transOrigPointerField'].'='.intval($orig_uid).
1150 t3lib_BEfunc::deleteClause($table).
1151 t3lib_BEfunc::versioningPlaceholderClause($table)
1152 );
1153
1154 if (is_array($localizedRecord)) {
1155 // Create parameters and finally run the classic page module for creating a new page translation
1156 $params = '&edit['.$table.']['.$localizedRecord['uid'].']=edit';
1157 $returnUrl = '&returnUrl='.rawurlencode(t3lib_div::_GP('returnUrl'));
1158 $location = $GLOBALS['BACK_PATH'].'alt_doc.php?'.$params.$returnUrl;
1159
1160 header('Location: '.t3lib_div::locationHeaderUrl($location));
1161 exit;
1162 }
1163 }
1164 }
1165
1166
1167 /**
1168 * Returns sys_language records.
1169 *
1170 * @param integer Page id: If zero, the query will select all sys_language records from root level which are NOT hidden. If set to another value, the query will select all sys_language records that has a pages_language_overlay record on that page (and is not hidden, unless you are admin user)
1171 * @return array Language records including faked record for default language
1172 */
1173 function getLanguages($id) {
1174 global $LANG;
1175
1176 $modSharedTSconfig = t3lib_BEfunc::getModTSconfig($id, 'mod.SHARED');
1177
1178 $languages = array(
1179 0 => array(
1180 'uid' => 0,
1181 'pid' => 0,
1182 'hidden' => 0,
1183 'title' => strlen($modSharedTSconfig['properties']['defaultLanguageLabel']) ? $modSharedTSconfig['properties']['defaultLanguageLabel'].' ('.$GLOBALS['LANG']->sl('LLL:EXT:lang/locallang_mod_web_list.xml:defaultLanguage').')' : $GLOBALS['LANG']->sl('LLL:EXT:lang/locallang_mod_web_list.xml:defaultLanguage'),
1184 'flag' => $modSharedTSconfig['properties']['defaultLanguageFlag'],
1185 )
1186 );
1187
1188 $exQ = $GLOBALS['BE_USER']->isAdmin() ? '' : ' AND sys_language.hidden=0';
1189 if ($id) {
1190 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
1191 'sys_language.*',
1192 'pages_language_overlay,sys_language',
1193 'pages_language_overlay.sys_language_uid=sys_language.uid AND pages_language_overlay.pid='.intval($id).$exQ,
1194 'pages_language_overlay.sys_language_uid,sys_language.uid,sys_language.pid,sys_language.tstamp,sys_language.hidden,sys_language.title,sys_language.static_lang_isocode,sys_language.flag',
1195 'sys_language.title'
1196 );
1197 } else {
1198 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
1199 'sys_language.*',
1200 'sys_language',
1201 'sys_language.hidden=0',
1202 '',
1203 'sys_language.title'
1204 );
1205 }
1206 if ($rows) {
1207 foreach ($rows as $row) {
1208 $languages[$row['uid']] = $row;
1209 }
1210 }
1211 return $languages;
1212 }
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223 /***************************
1224 *
1225 * Other functions
1226 *
1227 ***************************/
1228
1229 /**
1230 * Fix $this->editconf if versioning applies to any of the records
1231 *
1232 * @param array Mapping between old and new ids if auto-versioning has been performed.
1233 * @return void
1234 */
1235 function fixWSversioningInEditConf($mapArray=FALSE) {
1236 global $TCA,$BE_USER;
1237
1238 // Traverse the editConf array
1239 if (is_array($this->editconf)) {
1240 foreach($this->editconf as $table => $conf) { // Tables:
1241 if (is_array($conf) && $TCA[$table]) {
1242
1243 // Traverse the keys/comments of each table (keys can be a commalist of uids)
1244 $newConf = array();
1245 foreach($conf as $cKey => $cmd) {
1246 if ($cmd=='edit') {
1247 // Traverse the ids:
1248 $ids = t3lib_div::trimExplode(',', $cKey, 1);
1249 foreach($ids as $idKey => $theUid) {
1250 if (is_array($mapArray)) {
1251 if ($mapArray[$table][$theUid]) {
1252 $ids[$idKey] = $mapArray[$table][$theUid];
1253 }
1254 } else { // Default, look for versions in workspace for record:
1255 $calcPRec = $this->getRecordForEdit($table,$theUid);
1256 if (is_array($calcPRec)) {
1257 // Setting UID again if it had changed, eg. due to workspace versioning.
1258 $ids[$idKey] = $calcPRec['uid'];
1259 }
1260 }
1261 #else unset($ids[$idKey]);
1262 }
1263
1264 // Add the possibly manipulated IDs to the new-build newConf array:
1265 $newConf[implode(',',$ids)] = $cmd;
1266 } else {
1267 $newConf[$cKey] = $cmd;
1268 }
1269 }
1270 // Store the new conf array:
1271 $this->editconf[$table] = $newConf;
1272 }
1273 }
1274 }
1275 }
1276
1277 /**
1278 * Get record for editing.
1279 *
1280 * @param string Table name
1281 * @param integer Record UID
1282 * @return array Returns record to edit, false if none
1283 */
1284 function getRecordForEdit($table,$theUid) {
1285 global $TCA;
1286
1287 // Fetch requested record:
1288 $reqRecord = t3lib_BEfunc::getRecord($table,$theUid,'uid,pid');
1289
1290 if (is_array($reqRecord)) {
1291 // If workspace is OFFLINE:
1292 if ($GLOBALS['BE_USER']->workspace!=0) {
1293
1294 // Check for versioning support of the table:
1295 if ($TCA[$table] && $TCA[$table]['ctrl']['versioningWS']) {
1296
1297 // If the record is already a version of "something" pass it by.
1298 if ($reqRecord['pid']==-1) {
1299
1300 // (If it turns out not to be a version of the current workspace there will be trouble, but that is handled inside TCEmain then and in the interface it would clearly be an error of links if the user accesses such a scenario)
1301 return $reqRecord;
1302 } else { // The input record was online and an offline version must be found or made:
1303
1304 // Look for version of this workspace:
1305 $versionRec = t3lib_BEfunc::getWorkspaceVersionOfRecord($GLOBALS['BE_USER']->workspace, $table, $reqRecord['uid'],'uid,pid,t3ver_oid');
1306 return is_array($versionRec) ? $versionRec : $reqRecord;
1307 }
1308 } else return FALSE; // This means that editing cannot occur on this record because it was not supporting versioning which is required inside an offline workspace.
1309 } else return $reqRecord; // In ONLINE workspace, just return the originally requested record:
1310 } else return FALSE; // Return false because the table/uid was not found anyway.
1311 }
1312
1313 /**
1314 * Function, which populates the internal editconf array with editing commands for all tt_content elements from the normal column in normal language from the page pointed to by $this->editRegularContentFromId
1315 *
1316 * @return void
1317 */
1318 function editRegularContentFromId() {
1319 if (t3lib_extMgm::isLoaded('cms')) {
1320 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
1321 'uid',
1322 'tt_content',
1323 'pid='.intval($this->editRegularContentFromId).
1324 t3lib_BEfunc::deleteClause('tt_content').
1325 t3lib_BEfunc::versioningPlaceholderClause('tt_content').
1326 ' AND colPos=0 AND sys_language_uid=0',
1327 '',
1328 'sorting'
1329 );
1330 if ($GLOBALS['TYPO3_DB']->sql_num_rows($res)) {
1331 $ecUids=array();
1332 while($ecRec = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
1333 $ecUids[]=$ecRec['uid'];
1334 }
1335 $this->editconf['tt_content'][implode(',',$ecUids)]='edit';
1336 }
1337 }
1338 }
1339
1340 /**
1341 * Populates the variables $this->storeArray, $this->storeUrl, $this->storeUrlMd5
1342 *
1343 * @return void
1344 * @see makeDocSel()
1345 */
1346 function compileStoreDat() {
1347 $this->storeArray = t3lib_div::compileSelectedGetVarsFromArray('edit,defVals,overrideVals,columnsOnly,disHelp,noView,editRegularContentFromId',$this->R_URL_getvars);
1348 $this->storeUrl = t3lib_div::implodeArrayForUrl('',$this->storeArray);
1349 $this->storeUrlMd5 = md5($this->storeUrl);
1350 }
1351
1352 /**
1353 * Function used to look for configuration of buttons in the form: Fx. disabling buttons or showing them at various positions.
1354 *
1355 * @param string The table for which the configuration may be specific
1356 * @param string The option for look for. Default is checking if the saveDocNew button should be displayed.
1357 * @return string Return value fetched from USER TSconfig
1358 */
1359 function getNewIconMode($table, $key = 'saveDocNew') {
1360 $TSconfig = $GLOBALS['BE_USER']->getTSConfig('options.'.$key);
1361 $output = trim(isset($TSconfig['properties'][$table]) ? $TSconfig['properties'][$table] : $TSconfig['value']);
1362 if (($key == 'saveDocNew' || $key == 'saveDocView') && $TSconfig['value'] != '0') {
1363 $output = !(isset($TSconfig['properties'][$table]) && $TSconfig['properties'][$table] == '0');
1364 }
1365 return $output;
1366 }
1367
1368 /**
1369 * Handling the closing of a document
1370 *
1371 * @param integer Close code: 0/1 will redirect to $this->retUrl, 3 will clear the docHandler (thus closing all documents) and otehr values will call setDocument with ->retUrl
1372 * @return void
1373 */
1374 function closeDocument($code=0) {
1375 global $BE_USER;
1376
1377 // If current document is found in docHandler,
1378 // then unset it, possibly unset it ALL and finally, write it to the session data
1379 if (isset($this->docHandler[$this->storeUrlMd5])) {
1380
1381 // add the closing document to the recent documents
1382 $recentDocs = $BE_USER->getModuleData('opendocs::recent');
1383 if (!is_array($recentDocs)) {
1384 $recentDocs = array();
1385 }
1386 $closedDoc = $this->docHandler[$this->storeUrlMd5];
1387 $recentDocs = array_merge(array($this->storeUrlMd5 => $closedDoc), $recentDocs);
1388 if (count($recentDocs) > 8) {
1389 $recentDocs = array_slice($recentDocs, 0, 8);
1390 }
1391
1392 // remove it from the list of the open documents
1393 unset($this->docHandler[$this->storeUrlMd5]);
1394 if ($code == '3') {
1395 $recentDocs = array_merge($this->docHandler, $recentDocs);
1396 $this->docHandler = array();
1397 }
1398 $BE_USER->pushModuleData('opendocs::recent', $recentDocs);
1399 $BE_USER->pushModuleData('alt_doc.php', array($this->docHandler, $this->docDat[1]));
1400 t3lib_BEfunc::setUpdateSignal('tx_opendocs::updateNumber', count($this->docHandler));
1401 }
1402
1403
1404 // If ->returnEditConf is set, then add the current content of editconf to the ->retUrl variable: (used by other scripts, like wizard_add, to know which records was created or so...)
1405 if ($this->returnEditConf && $this->retUrl!='dummy.php') {
1406 $this->retUrl.='&returnEditConf='.rawurlencode(serialize($this->editconf));
1407 }
1408
1409 // If code is NOT set OR set to 1, then make a header location redirect to $this->retUrl
1410 if (!$code || $code==1) {
1411 Header('Location: '.t3lib_div::locationHeaderUrl($this->retUrl));
1412 exit;
1413 } else {
1414 $this->setDocument('',$this->retUrl);
1415 }
1416 }
1417
1418 /**
1419 * Redirects to the document pointed to by $currentDocFromHandlerMD5 OR $retUrl (depending on some internal calculations).
1420 * Most likely you will get a header-location redirect from this function.
1421 *
1422 * @param string Pointer to the document in the docHandler array
1423 * @param string Alternative/Default retUrl
1424 * @return void
1425 */
1426 function setDocument($currentDocFromHandlerMD5='',$retUrl='alt_doc_nodoc.php') {
1427 if (!t3lib_extMgm::isLoaded('cms') && !strcmp($retUrl,'alt_doc_nodoc.php')) return;
1428
1429 if (!$this->modTSconfig['properties']['disableDocSelector'] && is_array($this->docHandler) && count($this->docHandler)) {
1430 if (isset($this->docHandler[$currentDocFromHandlerMD5])) {
1431 $setupArr=$this->docHandler[$currentDocFromHandlerMD5];
1432 } else {
1433 reset($this->docHandler);
1434 $setupArr=current($this->docHandler);
1435 }
1436 if ($setupArr[2]) {
1437 $sParts = parse_url(t3lib_div::getIndpEnv('REQUEST_URI'));
1438 $retUrl = $sParts['path'].'?'.$setupArr[2].'&returnUrl='.rawurlencode($retUrl);
1439 }
1440 }
1441 Header('Location: '.t3lib_div::locationHeaderUrl($retUrl));
1442 exit;
1443 }
1444 }
1445
1446
1447 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/alt_doc.php']) {
1448 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/alt_doc.php']);
1449 }
1450
1451
1452
1453 // Make instance:
1454 $SOBE = t3lib_div::makeInstance('SC_alt_doc');
1455
1456 // Preprocessing, storing data if submitted to
1457 $SOBE->preInit();
1458 if ($SOBE->doProcessData()) { // Checks, if a save button has been clicked (or the doSave variable is sent)
1459 $SOBE->processData();
1460 }
1461
1462
1463 // Main:
1464 $SOBE->init();
1465 $SOBE->main();
1466 $SOBE->printContent();
1467
1468 ?>