0006087_v4.patch

Administrator Admin, 2008-02-03 21:00

Download (79.5 KB)

View differences:

t3lib/config_default.php (Revision 3042)
175 175
		'AJAX' => array(				// array of key-value pairs for a unified use of AJAX calls in the TYPO3 backend. Keys are the unique ajaxIDs where the value will be resolved to call a method in an object. See ajax.php and the classes/class.typo3ajax.php for more information.
176 176
			'SC_alt_db_navframe::expandCollapse'   => 'typo3/alt_db_navframe.php:SC_alt_db_navframe->ajaxExpandCollapse',
177 177
			'SC_alt_file_navframe::expandCollapse' => 'typo3/alt_file_navframe.php:SC_alt_file_navframe->ajaxExpandCollapse',
178
			't3lib_TCEforms_inline::createNewRecord'		    => 't3lib/class.t3lib_tceforms_inline.php:t3lib_TCEforms_inline->processAjaxRequest',
178
			't3lib_TCEforms_inline::createNewRecord'		=> 't3lib/class.t3lib_tceforms_inline.php:t3lib_TCEforms_inline->processAjaxRequest',
179
			't3lib_TCEforms_inline::synchronizeLocalizeRecords'	=> 't3lib/class.t3lib_tceforms_inline.php:t3lib_TCEforms_inline->processAjaxRequest',
179 180
			't3lib_TCEforms_inline::setExpandedCollapsedState'	=> 't3lib/class.t3lib_tceforms_inline.php:t3lib_TCEforms_inline->processAjaxRequest',
180 181
			'ShortcutMenu::getGroups'              => 'typo3/classes/class.shortcutmenu.php:ShortcutMenu->getAjaxShortcutGroups',
181 182
			'ShortcutMenu::saveShortcut'           => 'typo3/classes/class.shortcutmenu.php:ShortcutMenu->setAjaxShortcut',
t3lib/class.t3lib_tceforms.php (Revision 3042)
2 2
/***************************************************************
3 3
*  Copyright notice
4 4
*
5
*  (c) 1999-2006 Kasper Skaarhoj (kasperYYYY@typo3.com)
5
*  (c) 1999-2008 Kasper Skaarhoj (kasperYYYY@typo3.com)
6 6
*  All rights reserved
7 7
*
8 8
*  This script is part of the TYPO3 project. The TYPO3 project is
......
357 357
			'check' => array('cols', 'showIfRTE'),
358 358
			'select' => array('size', 'autoSizeMax', 'maxitems', 'minitems'),
359 359
			'group' => array('size', 'autoSizeMax', 'max_size', 'show_thumbs', 'maxitems', 'minitems'),
360
			'inline' => array('appearance', 'foreign_label', 'foreign_selector', 'foreign_unique', 'maxitems', 'minitems', 'size', 'autoSizeMax', 'symmetric_label'),
360
			'inline' => array('appearance', 'behaviour', 'foreign_label', 'foreign_selector', 'foreign_unique', 'maxitems', 'minitems', 'size', 'autoSizeMax', 'symmetric_label'),
361 361
		);
362 362

  
363 363
			// Create instance of t3lib_TCEforms_inline only if this a non-IRRE-AJAX call: 
......
3150 3150
			$dLVal = t3lib_BEfunc::getProcessedValue($table,$field,$this->defaultLanguageData[$table.':'.$row['uid']][$field],0,1);
3151 3151
			$fCfg = $GLOBALS['TCA'][$table]['columns'][$field];
3152 3152

  
3153
			if (strcmp($dLVal,''))	{
3154
				$item.='<div class="typo3-TCEforms-originalLanguageValue">'.$this->getLanguageIcon($table,$row,0).$this->previewFieldValue($dLVal,$fCfg).'&nbsp;</div>';
3155
			}
3153
				// Don't show content if it's for IRRE child records:
3154
			if (isset($fCfg['config']['type']) && $fCfg['config']['type']!='inline') {
3155
				if (strcmp($dLVal,''))	{
3156
					$item.='<div class="typo3-TCEforms-originalLanguageValue">'.$this->getLanguageIcon($table,$row,0).$this->previewFieldValue($dLVal,$fCfg).'&nbsp;</div>';
3157
				}
3156 3158

  
3157
			$prLang = $this->getAdditionalPreviewLanguages();
3158
			foreach($prLang as $prL)	{
3159
				$dlVal = t3lib_BEfunc::getProcessedValue($table,$field,$this->additionalPreviewLanguageData[$table.':'.$row['uid']][$prL['uid']][$field],0,1);
3159
				$prLang = $this->getAdditionalPreviewLanguages();
3160
				foreach($prLang as $prL)	{
3161
					$dlVal = t3lib_BEfunc::getProcessedValue($table,$field,$this->additionalPreviewLanguageData[$table.':'.$row['uid']][$prL['uid']][$field],0,1);
3160 3162

  
3161
				if(strcmp($dlVal, '')) {
3162
					$item.= '<div class="typo3-TCEforms-originalLanguageValue">'.$this->getLanguageIcon($table, $row, 'v'.$prL['ISOcode']).$this->previewFieldValue($dlVal, $fCfg).'&nbsp;</div>';
3163
					if(strcmp($dlVal, '')) {
3164
						$item.= '<div class="typo3-TCEforms-originalLanguageValue">'.$this->getLanguageIcon($table, $row, 'v'.$prL['ISOcode']).$this->previewFieldValue($dlVal, $fCfg).'&nbsp;</div>';
3165
					}
3163 3166
				}
3164 3167
			}
3165

  
3166 3168
		}
3167 3169

  
3168 3170
		return $item;
t3lib/jsfunc.inline.js (Revision 3042)
9 9
*
10 10
*  Copyright notice
11 11
*
12
*  (c) 2006-2007 Oliver Hader <oh@inpublica.de>
12
*  (c) 2006-2008 Oliver Hader <oh@inpublica.de>
13 13
*  All rights reserved
14 14
*
15 15
*  This script is part of the TYPO3 project. The TYPO3 project is
......
102 102
		if (ucFormObj.length) ucFormObj[0].value = value;
103 103
	},
104 104

  
105
	createNewRecord: function(objectId,prevRecordUid) {
105
	createNewRecord: function(objectId, recordUid) {
106 106
		if (this.isBelowMax(objectId)) {
107
			if (prevRecordUid) {
108
				objectId += '['+prevRecordUid+']';
107
			if (recordUid) {
108
				objectId += '['+recordUid+']';
109 109
			}
110 110
			this.makeAjaxCall('createNewRecord', [this.getNumberOfRTE(), objectId], true);
111 111
		} else {
......
114 114
		return false;
115 115
	},
116 116

  
117
	synchronizeLocalizeRecords: function(objectId, type) {
118
		var parameters = [this.getNumberOfRTE(), objectId, type];
119
		this.makeAjaxCall('synchronizeLocalizeRecords', parameters, true);
120
	},
121

  
117 122
	setExpandedCollapsedState: function(objectId, expand, collapse) {
118 123
		this.makeAjaxCall('setExpandedCollapsedState', [objectId, expand, collapse]);
119 124
	},
......
597 602
		if (this.data.unique && this.data.unique[objectPrefix]) {
598 603
			var unique = this.data.unique[objectPrefix];
599 604
			var fieldObj = elName ? document.getElementsByName(elName+'['+unique.field+']') : null;
600
	
605

  
601 606
			if (unique.type == 'select') {
602 607
				if (fieldObj && fieldObj.length) {
603 608
					delete(this.data.unique[objectPrefix].used[recordUid])
604
	
609

  
605 610
					if (unique.selector == 'select') {
606 611
						if (!isNaN(fieldObj[0].value)) {
607 612
							var selector = $(objectPrefix+'_selector');
608 613
							this.readdSelectOption(selector, fieldObj[0].value, unique);
609 614
						}
610 615
					}
611
	
616

  
612 617
					if (!(unique.selector && unique.max == -1)) {
613 618
						var formName = this.prependFormFieldNames+this.parseFormElementName('parts', objectPrefix, 3, 1);
614 619
						var formObj = document.getElementsByName(formName);
......
646 651
		return false;
647 652
	},
648 653

  
649
	deleteRecord: function(objectId) {
654
	deleteRecord: function(objectId, options) {
650 655
		var i, j, inlineRecords, records, childObjectId, childTable;
651 656
		var objectPrefix = this.parseFormElementName('full', objectId, 0 , 1);
652 657
		var elName = this.parseFormElementName('full', objectId, 2);
......
677 682
		}
678 683

  
679 684
			// If the record is new and was never saved before, just remove it from DOM:
680
		if (this.isNewRecord(objectId)) {
681
			new Effect.Fade(objectId+'_div', { afterFinish: function() { Element.remove(objectId+'_div'); }	});
685
		if (this.isNewRecord(objectId) || options && options.forceDirectRemoval) {
686
			this.fadeAndRemove(objectId+'_div');
682 687
			// If the record already exists in storage, mark it to be deleted on clicking the save button:
683 688
		} else {
684 689
			document.getElementsByName('cmd'+shortName+'[delete]')[0].disabled = false;
......
879 884
  			md5 = this.data.config[objectPrefix].md5;
880 885
  		}
881 886
  		return md5
887
  	},
888

  
889
  	fadeAndRemove: function(element) {
890
  		if ($(element)) {
891
			new Effect.Fade(element, { afterFinish: function() { Element.remove(element); }	});
892
		}
882 893
  	}
883 894
}
884 895

  
t3lib/class.t3lib_befunc.php (Revision 3042)
441 441
		return $outQ;
442 442
	}
443 443

  
444
	/**
445
	 * Fetches the localization for a given record.
446
	 *
447
	 * @param	string		$table: Table name present in $TCA
448
	 * @param	integer		$uid: The uid of the record
449
	 * @param	?nteger		$language: The uid of the language record in sys_language
450
	 * @param	string		$andWhereClause: Optional additional WHERE clause (default: '')
451
	 * @return	mixed		Multidimensional array with selected records; if none exist, false is returned
452
	 */
453
	public function getRecordLocalization($table, $uid, $language, $andWhereClause='') {
454
		$recordLocalization = false; 
455
		if (isset($GLOBALS['TCA'][$table]['ctrl'])) {
456
			$tcaCtrl =& $GLOBALS['TCA'][$table]['ctrl'];
457
			if (isset($tcaCtrl['transOrigPointerField']) && isset($tcaCtrl['languageField'])) {
458
				$recordLocalization = t3lib_BEfunc::getRecordsByField(
459
					$table,
460
					$tcaCtrl['transOrigPointerField'],
461
					$uid,
462
					'AND '.$tcaCtrl['languageField'].'='.intval($language).($andWhereClause ? ' '.$andWhereClause : ''),
463
					'',
464
					'',
465
					'1'
466
				);
467
			}
468
		}
469
		return $recordLocalization;		
470
	}
444 471

  
445 472

  
446 473

  
......
450 477

  
451 478

  
452 479

  
480

  
453 481
	/*******************************************
454 482
	 *
455 483
	 * SQL-related, DEPRECATED functions
......
813 841
	}
814 842

  
815 843
	/**
844
	 * Determines whether a table is localizable and has the languageField and transOrigPointerField set in $TCA.
845
	 *
846
	 * @param	string		$table: The table to check
847
	 * @return	boolean		Whether a table is localizable
848
	 */
849
	public function isTableLocalizable($table) {
850
		$isLocalizable = false;
851
		if (isset($GLOBALS['TCA'][$table]['ctrl']) && is_array($GLOBALS['TCA'][$table]['ctrl'])) {
852
			$tcaCtrl =& $GLOBALS['TCA'][$table]['ctrl'];
853
			$isLocalizable = (isset($tcaCtrl['languageField']) && $tcaCtrl['languageField'] && isset($tcaCtrl['transOrigPointerField']) && $tcaCtrl['transOrigPointerField']);
854
		}
855
		return $isLocalizable;
856
	}
857

  
858
	/**
859
	 * Returns the value of the property localizationMode in the given $config array ($TCA[<table>]['columns'][<field>]['config']).
860
	 * If the table is prepared for localization and no localizationMode is set, 'select' is returned by default.
861
	 * If the table is not prepared for localization or not defined at all in $TCA, false is returned.
862
	 *
863
	 * @param	string		$table: The name of the table to lookup in TCA
864
	 * @param	mixed		$fieldOrConfig: The fieldname (string) or the configuration of the field to check (array) 
865
	 * @return	mixed		If table is localizable, the set localizationMode is returned (if property is not set, 'select' is returned by default); if table is not localizable, false is returned 
866
	 */
867
	public function getInlineLocalizationMode($table, $fieldOrConfig) {
868
		$localizationMode = false;
869
		if (is_array($fieldOrConfig) && count($fieldOrConfig)) {	
870
			$config = $fieldOrConfig;
871
		} elseif (is_string($fieldOrConfig) && isset($GLOBALS['TCA'][$table]['columns'][$field]['config'])) {
872
			$config = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
873
		}
874
		if (is_array($config) && isset($config['type']) && $config['type']=='inline' && self::isTableLocalizable($table)) {
875
			$localizationMode = (isset($config['behaviour']['localizationMode']) && $config['behaviour']['localizationMode'] ? $config['behaviour']['localizationMode'] : 'select');
876
				// The mode 'select' is not possible when child table is not localizable at all:
877
			if ($localizationMode=='select' && !self::isTableLocalizable($config['foreign_table'])) {
878
				$localizationMode = false; 
879
			}
880
		}
881
		return $localizationMode;
882
	}
883

  
884
	/**
816 885
	 * Returns a page record (of page with $id) with an extra field "_thePath" set to the record path IF the WHERE clause, $perms_clause, selects the record. Thus is works as an access check that returns a page record if access was granted, otherwise not.
817 886
	 * If $id is zero a pseudo root-page with "_thePath" set is returned IF the current BE_USER is admin.
818 887
	 * In any case ->isInWebMount must return true for the user (regardless of $perms_clause)
t3lib/class.t3lib_tceforms_inline.php (Revision 3042)
2 2
/***************************************************************
3 3
*  Copyright notice
4 4
*
5
*  (c) 2006-2007 Oliver Hader <oh@inpublica.de>
5
*  (c) 2006-2008 Oliver Hader <oh@inpublica.de>
6 6
*  All rights reserved
7 7
*
8 8
*  This script is part of the TYPO3 project. The TYPO3 project is
......
141 141
	 */
142 142
	function getSingleField_typeInline($table,$field,$row,&$PA) {
143 143
			// check the TCA configuration - if false is returned, something was wrong
144
		if ($this->checkConfiguration($PA['fieldConf']['config']) === false) return false;
144
		if ($this->checkConfiguration($PA['fieldConf']['config']) === false) {
145
			return false;
146
		}
145 147

  
146 148
			// count the number of processed inline elements
147 149
		$this->inlineCount++;
......
151 153
		$foreign_table = $config['foreign_table'];
152 154
		t3lib_div::loadTCA($foreign_table);
153 155

  
156
		if (t3lib_BEfunc::isTableLocalizable($table)) {
157
			$language = intval($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]);
158
		}
154 159
		$minitems = t3lib_div::intInRange($config['minitems'],0);
155 160
		$maxitems = t3lib_div::intInRange($config['maxitems'],0);
156 161
		if (!$maxitems)	$maxitems=100000;
......
186 191
			// e.g. inline[<pid>][<table1>][<uid1>][<field1>][<table2>][<uid2>][<field2>]
187 192
		$nameObject = $this->inlineNames['object'];
188 193
			// get the records related to this inline record
189
		$recordList = $this->getRelatedRecords($table,$field,$row,$PA,$config);
194
		$relatedRecords = $this->getRelatedRecords($table,$field,$row,$PA,$config);
190 195
			// set the first and last record to the config array
191
		$config['inline']['first'] = $recordList[0]['uid'];
192
		$config['inline']['last'] = $recordList[count($recordList)-1]['uid'];
196
		$config['inline']['first'] = $relatedRecords['records'][0]['uid'];
197
		$config['inline']['last'] = $relatedRecords['records'][$relatedRecords['count']-1]['uid'];
193 198

  
194 199
			// Tell the browser what we have (using JSON later):
195 200
		$top = $this->getStructureLevel(0);
......
214 219
				// If uniqueness *and* selector are set, they should point to the same field - so, get the configuration of one:
215 220
			$selConfig = $this->getPossibleRecordsSelectorConfig($config, $config['foreign_unique']);
216 221
				// Get the used unique ids:
217
			$uniqueIds = $this->getUniqueIds($recordList, $config, $selConfig['type']=='groupdb');
222
			$uniqueIds = $this->getUniqueIds($relatedRecords['records'], $config, $selConfig['type']=='groupdb');
218 223
			$possibleRecords = $this->getPossibleRecords($table,$field,$row,$config,'foreign_unique');
219 224
			$uniqueMax = $config['appearance']['useCombination'] || $possibleRecords === false ? -1	: count($possibleRecords);
220 225
			$this->inlineData['unique'][$nameObject.'['.$foreign_table.']'] = array(
......
244 249
		$item .= '<div id="'.$nameObject.'">';
245 250

  
246 251
			// define how to show the "Create new record" link - if there are more than maxitems, hide it
247
		if (count($recordList) >= $maxitems || ($uniqueMax > 0 && count($recordList) >= $uniqueMax)) {
252
		if ($relatedRecords['count'] >= $maxitems || ($uniqueMax > 0 && $relatedRecords['count'] >= $uniqueMax)) {
248 253
			$config['inline']['inlineNewButtonStyle'] = 'display: none;';
249 254
		}
250
			// add the "Create new record" link before all child records
251
		if (in_array($config['appearance']['newRecordLinkPosition'], array('both', 'top'))) {
252
			$item .= $this->getNewRecordLink($nameObject.'['.$foreign_table.']', $config);
255

  
256
			// Render the level links (create new record, localize all, synchronize):
257
		if ($config['appearance']['levelLinksPosition']!='none') {
258
			$levelLinks = $this->getLevelInteractionLink('newRecord', $nameObject.'['.$foreign_table.']', $config);
259
			if ($language>0) {
260
					// Add the "Localize all records" link before all child records:
261
				if (isset($config['appearance']['showAllLocalizationLink']) && $config['appearance']['showAllLocalizationLink']) {
262
					$levelLinks.= $this->getLevelInteractionLink('localize', $nameObject.'['.$foreign_table.']', $config);
263
				} 
264
					// Add the "Synchronize with default language" link before all child records:
265
				if (isset($config['appearance']['showSynchronizationLink']) && $config['appearance']['showSynchronizationLink']) {
266
					$levelLinks.= $this->getLevelInteractionLink('synchronize', $nameObject.'['.$foreign_table.']', $config);
267
				}	
268
			}
253 269
		}
270
			// Add the level links before all child records:
271
		if (in_array($config['appearance']['levelLinksPosition'], array('both', 'top'))) {
272
			$item.= $levelLinks;
273
		}
254 274

  
255 275
		$item .= '<div id="'.$nameObject.'_records">';
256 276
		$relationList = array();
257
		if (count($recordList)) {
258
			foreach ($recordList as $rec) {
277
		if (count($relatedRecords['records'])) {
278
			foreach ($relatedRecords['records'] as $rec) {
259 279
				$item .= $this->renderForeignRecord($row['uid'],$rec,$config);
260
				$relationList[] = $rec['uid'];
280
				if (!isset($rec['__virtual']) || !$rec['__virtual']) {
281
					$relationList[] = $rec['uid'];
282
				}
261 283
			}
262 284
		}
263 285
		$item .= '</div>';
264 286

  
265
			// add the "Create new record" link after all child records
266
		if (in_array($config['appearance']['newRecordLinkPosition'], array('both', 'bottom'))) {
267
			$item .= $this->getNewRecordLink($nameObject.'['.$foreign_table.']', $config);
287
			// Add the level links after all child records:
288
		if (in_array($config['appearance']['levelLinksPosition'], array('both', 'bottom'))) {
289
			$item.= $levelLinks;
268 290
		}
269 291

  
270 292
			// add Drag&Drop functions for sorting to TCEforms::$additionalJS_post
......
307 329
		$foreign_field = $config['foreign_field'];
308 330
		$foreign_selector = $config['foreign_selector'];
309 331

  
332
			// Register default localization content:
333
		$parent = $this->getStructureLevel(-1);
334
		if (isset($parent['localizationMode']) && $parent['localizationMode']!=false) {
335
			$this->fObj->registerDefaultLanguageData($foreign_table, $rec);
336
		}
310 337
			// Send a mapping information to the browser via JSON:
311 338
			// e.g. data[<curTable>][<curId>][<curField>] => data[<pid>][<parentTable>][<parentId>][<parentField>][<curTable>][<curId>][<curField>]
312 339
		$this->inlineData['map'][$this->inlineNames['form']] = $this->inlineNames['object'];
313 340

  
314 341
			// Set this variable if we handle a brand new unsaved record:
315 342
		$isNewRecord = t3lib_div::testInt($rec['uid']) ? false : true;
343
			// Set this variable if the record is virtual and only show with header and not editable fields:
344
		$isVirtualRecord = (isset($rec['__virtual']) && $rec['__virtual']);
316 345
			// If there is a selector field, normalize it:
317 346
		if ($foreign_selector) {
318 347
			$rec[$foreign_selector] = $this->normalizeUid($rec[$foreign_selector]);
319 348
		}
320 349

  
321
		$hasAccess = $this->checkAccess($isNewRecord?'new':'edit', $foreign_table, $rec['uid']);
350
		if (!$this->checkAccess(($isNewRecord ? 'new' : 'edit'), $foreign_table, $rec['uid'])) {
351
			return false;
352
		}
322 353

  
323
		if(!$hasAccess) return false;
324

  
325 354
			// Get the current naming scheme for DOM name/id attributes:
326 355
		$nameObject = $this->inlineNames['object'];
327 356
		$appendFormFieldNames = '['.$foreign_table.']['.$rec['uid'].']';
......
329 358
			// Put the current level also to the dynNestedStack of TCEforms:
330 359
		$this->fObj->pushToDynNestedStack('inline', $this->inlineNames['object'].$appendFormFieldNames);
331 360

  
332
		$header = $this->renderForeignRecordHeader($parentUid, $foreign_table, $rec, $config);
333
		$combination = $this->renderCombinationTable($rec, $appendFormFieldNames, $config);
334
		$fields = $this->renderMainFields($foreign_table, $rec);
335
		$fields = $this->wrapFormsSection($fields);
361
		$header = $this->renderForeignRecordHeader($parentUid, $foreign_table, $rec, $config, $isVirtualRecord);
362
		if (!$isVirtualRecord) {
363
			$combination = $this->renderCombinationTable($rec, $appendFormFieldNames, $config);
364
			$fields = $this->renderMainFields($foreign_table, $rec);
365
			$fields = $this->wrapFormsSection($fields);
336 366

  
337
		if ($isNewRecord) {
338
				// show this record expanded or collapsed
339
			$isExpanded = is_array($config['appearance']) && $config['appearance']['collapseAll'] ? 1 : 0;
340
				// get the top parent table
341
			$top = $this->getStructureLevel(0);
342
			$ucFieldName = 'uc['.$top['table'].']['.$top['uid'].']'.$appendFormFieldNames;
343
				// set additional fields for processing for saving
344
			$fields .= '<input type="hidden" name="'.$this->prependFormFieldNames.$appendFormFieldNames.'[pid]" value="'.$rec['pid'].'"/>';
345
			$fields .= '<input type="hidden" name="'.$ucFieldName.'" value="'.$isExpanded.'" />';
367
			if ($isNewRecord) {
368
					// show this record expanded or collapsed
369
				$isExpanded = is_array($config['appearance']) && $config['appearance']['collapseAll'] ? 1 : 0;
370
					// get the top parent table
371
				$top = $this->getStructureLevel(0);
372
				$ucFieldName = 'uc['.$top['table'].']['.$top['uid'].']'.$appendFormFieldNames;
373
					// set additional fields for processing for saving
374
				$fields .= '<input type="hidden" name="'.$this->prependFormFieldNames.$appendFormFieldNames.'[pid]" value="'.$rec['pid'].'"/>';
375
				$fields .= '<input type="hidden" name="'.$ucFieldName.'" value="'.$isExpanded.'" />';
346 376

  
347
		} else {
348
				// show this record expanded or collapsed
349
			$isExpanded = $this->getExpandedCollapsedState($foreign_table, $rec['uid']);
350
				// set additional field for processing for saving
351
			$fields .= '<input type="hidden" name="'.$this->prependCmdFieldNames.$appendFormFieldNames.'[delete]" value="1" disabled="disabled" />';
377
			} else {
378
					// show this record expanded or collapsed
379
				$isExpanded = $this->getExpandedCollapsedState($foreign_table, $rec['uid']);
380
					// set additional field for processing for saving
381
				$fields .= '<input type="hidden" name="'.$this->prependCmdFieldNames.$appendFormFieldNames.'[delete]" value="1" disabled="disabled" />';
382
			}
383

  
384
				// if this record should be shown collapsed
385
			if (!$isExpanded) $appearanceStyleFields = ' style="display: none;"';
352 386
		}
353 387

  
354
			// if this record should be shown collapsed
355
		if (!$isExpanded) $appearanceStyleFields = ' style="display: none;"';
356

  
357 388
			// set the record container with data for output
358 389
		$out = '<div id="'.$formFieldNames.'_header">'.$header.'</div>';
359 390
		$out .= '<div id="'.$formFieldNames.'_fields"'.$appearanceStyleFields.'>'.$fields.$combination.'</div>';
......
400 431
	 * @param	string		$foreign_table: The foreign_table we create a header for
401 432
	 * @param	array		$rec: The current record of that foreign_table
402 433
	 * @param	array		$config: content of $PA['fieldConf']['config']
434
	 * @param	boolean		$isVirtualRecord: 
403 435
	 * @return	string		The HTML code of the header
404 436
	 */
405
	function renderForeignRecordHeader($parentUid, $foreign_table, $rec, $config = array()) {
437
	function renderForeignRecordHeader($parentUid, $foreign_table, $rec, $config, $isVirtualRecord=false) {
406 438
			// Init:
407 439
		$formFieldNames = $this->inlineNames['object'].'['.$foreign_table.']['.$rec['uid'].']';
408 440
		$expandSingle = $config['appearance']['expandSingle'] ? 1 : 0;
......
453 485
		}
454 486

  
455 487
		$altText = t3lib_BEfunc::getRecordIconAltText($rec, $foreign_table);
456
		$iconImg =
457
			'<a href="#" onclick="'.htmlspecialchars($onClick).'">'.t3lib_iconWorks::getIconImage(
458
				$foreign_table, $rec, $this->backPath,
459
				'title="'.htmlspecialchars($altText).'" class="absmiddle"'
460
			).'</a>';
488
		$iconImg = t3lib_iconWorks::getIconImage($foreign_table, $rec, $this->backPath, 'title="'.htmlspecialchars($altText).'" class="absmiddle"');
489
		$label = '<span id="'.$formFieldNames.'_label">'.$recTitle.'</span>';
490
		if (!$isVirtualRecord) {
491
			$iconImg = $this->wrapWithAnchor($iconImg, '#', array('onclick' => $onClick));
492
			$label = $this->wrapWithAnchor($label, '#', array('onclick' => $onClick, 'style' => 'display: block;'));
493
		}
461 494

  
462
		$label =
463
			'<a href="#" onclick="'.htmlspecialchars($onClick).'" style="display: block;">'.
464
				'<span id="'.$formFieldNames.'_label">'.$recTitle.'</span>'.
465
			'</a>';
495
		$ctrl = $this->renderForeignRecordHeaderControl($parentUid, $foreign_table, $rec, $config, $isVirtualRecord);
466 496

  
467
		$ctrl = $this->renderForeignRecordHeaderControl($parentUid, $foreign_table, $rec, $config);
468

  
469 497
			// @TODO: Check the table wrapping and the CSS definitions
470 498
		$header =
471 499
			'<table cellspacing="0" cellpadding="0" border="0" width="100%" style="margin-right: '.$this->inlineStyles['margin-right'].'px;"'.
......
487 515
	 * @param	array		$config: (modified) TCA configuration of the field
488 516
	 * @return	string		The HTML code with the control-icons
489 517
	 */
490
	function renderForeignRecordHeaderControl($parentUid, $foreign_table, $rec, $config = array()) {
518
	function renderForeignRecordHeaderControl($parentUid, $foreign_table, $rec, $config=array(), $isVirtualRecord=false) {
491 519
			// Initialize:
492 520
		$cells = array();
493 521
		$isNewItem = substr($rec['uid'], 0, 3) == 'NEW';
......
518 546
			// Icon to visualize that a required field is nested in this inline level:
519 547
		$cells[] = '<img name="'.$nameObjectFtId.'_req" src="clear.gif" width="10" height="10" hspace="4" vspace="3" alt="" />';
520 548

  
549
		if (isset($rec['__create'])) {
550
			$cells[] = '<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/localize_green.gif','width="16" height="16"').' title="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_list.xml:unHide'.($isPagesTable?'Page':''),1).'" alt="" />';
551
		} elseif (isset($rec['__remove'])) {
552
			$cells[] = '<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/localize_red.gif','width="16" height="16"').' title="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_list.xml:unHide'.($isPagesTable?'Page':''),1).'" alt="" />';
553
		}
554

  
521 555
			// "Info": (All records)
522
		if (!$isNewItem)
556
		if (!$isNewItem) {
523 557
			$cells[]='<a href="#" onclick="'.htmlspecialchars('top.launchView(\''.$foreign_table.'\', \''.$rec['uid'].'\'); return false;').'">'.
524 558
				'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/zoom2.gif','width="12" height="12"').' title="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_list.xml:showInfo',1).'" alt="" />'.
525 559
				'</a>';
526

  
560
		}
527 561
			// If the table is NOT a read-only table, then show these links:
528
		if (!$tcaTableCtrl['readOnly'])	{
562
		if (!$tcaTableCtrl['readOnly'] && !$isVirtualRecord)	{
529 563

  
530 564
				// "New record after" link (ONLY if the records in the table are sorted by a "sortby"-row or if default values can depend on previous record):
531 565
			if ($enableManualSorting || $tcaTableCtrl['useColumnsForDefaultValues'])	{
......
580 614
			}
581 615

  
582 616
				// "Delete" link:
583
			if (
584
				($isPagesTable && ($localCalcPerms&4)) || (!$isPagesTable && ($calcPerms&16))
585
				)	{
617
			if ($isPagesTable && $localCalcPerms&4 || !$isPagesTable && $calcPerms&16) {
586 618
				$onClick = "inline.deleteRecord('".$nameObjectFtId."');";
587 619
				$cells[]='<a href="#" onclick="'.htmlspecialchars('if (confirm('.$GLOBALS['LANG']->JScharCode($GLOBALS['LANG']->getLL('deleteWarning')).')) {	'.$onClick.' } return false;').'">'.
588 620
						'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/garbage.gif','width="11" height="12"').' title="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_list.xml:delete',1).'" alt="" />'.
589 621
						'</a>';
590 622
			}
623
			// If this is a virtual record offer a minimized set of icons for user interaction:
624
		} elseif ($isVirtualRecord) {
625
			if (isset($rec['__create'])) {
626
				$onClick = "inline.synchronizeLocalizeRecords('".$nameObjectFt."', ".$rec['uid'].");";
627
				$cells[] = '<a href="#" onclick="'.htmlspecialchars($onClick).'">' . 
628
					'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/localize_el.gif','width="16" height="16"').' title="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:localize', 1).'" alt="" />' .
629
					'</a>';
630
			}
591 631
		}
592 632

  
593 633
			// If the record is edit-locked	by another user, we will show a little warning sign:
......
783 823

  
784 824

  
785 825
	/**
826
	 * Creates the HTML code of a general link to be used on a level of inline children.
827
	 * The possible keys for the parameter $type are 'newRecord', 'localize' and 'synchronize'.
828
	 *
829
	 * @param	string		$type: The link type, values are 'newRecord', 'localize' and 'synchronize'.
830
	 * @param	string		$objectPrefix: The "path" to the child record to create (e.g. 'data[parten_table][parent_uid][parent_field][child_table]')
831
	 * @param	array		$conf: TCA configuration of the parent(!) field
832
	 * @return	string		The HTML code of the new link, wrapped in a div
833
	 */
834
	protected function getLevelInteractionLink($type, $objectPrefix, $conf=array()) {
835
		$nameObject = $this->inlineNames['object'];
836
		$attributes = array();
837
		switch($type) {
838
			case 'newRecord':
839
				$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:cm.createnew', 1);
840
				$iconFile = 'gfx/new_el.gif';
841
				// $iconAddon = 'width="11" height="12"';
842
				$className = 'typo3-newRecordLink';
843
				$attributes['class'] = 'inlineNewButton '.$this->inlineData['config'][$nameObject]['md5'];
844
				$attributes['onclick'] = "return inline.createNewRecord('$objectPrefix')";
845
				if (isset($conf['inline']['inlineNewButtonStyle']) && $conf['inline']['inlineNewButtonStyle']) {
846
					$attributes['style'] = $conf['inline']['inlineNewButtonStyle'];
847
				}
848
				if (isset($conf['appearance']['newRecordLinkAddTitle']) && $conf['appearance']['newRecordLinkAddTitle']) {
849
					$titleAddon = ' '.$GLOBALS['LANG']->sL($GLOBALS['TCA'][$conf['foreign_table']]['ctrl']['title'], 1);
850
				}
851
				break;
852
			case 'localize':
853
				$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:localizeAllRecords', 1);
854
				$iconFile = 'gfx/localize_el.gif';
855
				$className = 'typo3-localizationLink';
856
				$attributes['onclick'] = "return inline.synchronizeLocalizeRecords('$objectPrefix', 'localize')";
857
				break;
858
			case 'synchronize':
859
				$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:synchronizeWithOriginalLanguage', 1);
860
				$iconFile = 'gfx/synchronize_el.gif';
861
				$className = 'typo3-synchronizationLink';
862
				$attributes['class'] = 'inlineNewButton '.$this->inlineData['config'][$nameObject]['md5'];
863
				$attributes['onclick'] = "return inline.synchronizeLocalizeRecords('$objectPrefix', 'synchronize')";
864
				break;
865
		}
866
			// Create the link:
867
		$icon = ($iconFile ? '<img'.t3lib_iconWorks::skinImg($this->backPath, $iconFile, $iconAddon).' alt="'.htmlspecialchars($title.$titleAddon).'" />' : '');
868
		$link = $this->wrapWithAnchor($icon.$title.$titleAddon, '#', $attributes);
869
		return '<div'.($className ? ' class="'.$className.'"' : '').$link.'</div>';
870
	}
871

  
872

  
873
	/**
786 874
	 * Creates a link/button to create new records
787 875
	 *
788 876
	 * @param	string		$objectPrefix: The "path" to the child record to create (e.g. '[parten_table][parent_uid][parent_field][child_table]')
789 877
	 * @param	array		$conf: TCA configuration of the parent(!) field
790 878
	 * @return	string		The HTML code for the new record link
879
	 * @deprecated	since TYPO3 4.2.0-beta1
791 880
	 */
792 881
	function getNewRecordLink($objectPrefix, $conf = array()) {
793
		$nameObject = $this->inlineNames['object'];
794
		$class = ' class="inlineNewButton '.$this->inlineData['config'][$nameObject]['md5'].'"';
795

  
796
		if ($conf['inline']['inlineNewButtonStyle']) {
797
			$style = ' style="'.$conf['inline']['inlineNewButtonStyle'].'"';
798
		}
799

  
800
		$onClick = "return inline.createNewRecord('$objectPrefix')";
801
		$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:cm.createnew',1);
802

  
803
		if ($conf['appearance']['newRecordLinkAddTitle']) {
804
			$tableTitle .= ' '.$GLOBALS['LANG']->sL($GLOBALS['TCA'][$conf['foreign_table']]['ctrl']['title'],1);
805
		}
806

  
807
		$out = '
808
				<div class="typo3-newRecordLink">
809
					<a href="#" onClick="'.$onClick.'"'.$class.$style.' title="'.$title.$tableTitle.'">'.
810
					'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/new_el.gif','width="11" height="12"').' alt="'.$title.$tableTitle.'" />'.
811
					$title.t3lib_div::fixed_lgd_cs($tableTitle, $this->fObj->titleLen).
812
					'</a>
813
				</div>';
814
		return $out;
882
		return $this->getLevelInteractionLink('newRecord', $objectPrefix, $conf);
815 883
	}
816 884

  
817 885

  
......
851 919
			$ajaxMethod = $ajaxIdParts[1];
852 920
			switch ($ajaxMethod) {
853 921
				case 'createNewRecord':
922
				case 'synchronizeLocalizeRecords':
923
					$this->isAjaxCall = true;
924
						// Construct runtime environment for Inline Relational Record Editing:
854 925
					$this->processAjaxRequestConstruct($ajaxArguments);
926
						// Parse the DOM identifier (string), add the levels to the structure stack (array) and load the TCA config:
927
					$this->parseStructureString($ajaxArguments[0], true);
928
						// Render content:
855 929
					$ajaxObj->setContentFormat('jsonbody');
856 930
					$ajaxObj->setContent(
857 931
						call_user_func_array(array(&$this, $ajaxMethod), $ajaxArguments)
......
924 998

  
925 999

  
926 1000
	/**
1001
	 * Determines and sets several script calls to a JSON array, that would have been executed if processed in non-AJAX mode.
1002
	 *
1003
	 * @param	array		&$jsonArray: Reference of the array to be used for JSON
1004
	 * @param	array		$config: The configuration of the IRRE field of the parent record
1005
	 * @return	void 
1006
	 */
1007
	protected function getCommonScriptCalls(&$jsonArray, $config) {
1008
			// Add data that would have been added at the top of a regular TCEforms call:
1009
		if ($headTags = $this->getHeadTags()) {
1010
			$jsonArray['headData'] = $headTags;
1011
		}
1012
			// Add the JavaScript data that would have been added at the bottom of a regular TCEforms call:
1013
		$jsonArray['scriptCall'][] = $this->fObj->JSbottom($this->fObj->formName, true);
1014
			// If script.aculo.us Sortable is used, update the Observer to know the record:
1015
		if ($config['appearance']['useSortable']) {
1016
			$jsonArray['scriptCall'][] = "inline.createDragAndDropSorting('".$this->inlineNames['object']."_records');";
1017
		}
1018
			// if TCEforms has some JavaScript code to be executed, just do it
1019
		if ($this->fObj->extJSCODE) {
1020
			$jsonArray['scriptCall'][] = $this->fObj->extJSCODE;
1021
		}
1022
	}
1023

  
1024

  
1025
	/**
927 1026
	 * Initialize environment for AJAX calls
928 1027
	 *
929 1028
	 * @param	string		$method: Name of the method to be called
......
948 1047
	 * @return	array		An array to be used for JSON
949 1048
	 */
950 1049
	function createNewRecord($domObjectId, $foreignUid = 0) {
951
		$this->isAjaxCall = true;
952
			// parse the DOM identifier (string), add the levels to the structure stack (array) and load the TCA config
953
		$this->parseStructureString($domObjectId, true);
954 1050
			// the current table - for this table we should add/import records
955 1051
		$current = $this->inlineStructure['unstable'];
956 1052
			// the parent table - this table embeds the current table
......
964 1060
			// dynamically create a new record using t3lib_transferData
965 1061
		if (!$foreignUid || !t3lib_div::testInt($foreignUid) || $config['foreign_selector']) {
966 1062
			$record = $this->getNewRecord($this->inlineFirstPid, $current['table']);
1063
				// Set language of new child record to the language of the parent record:
1064
			if ($config['localizationMode']=='select') {
1065
				$parentRecord = $this->getRecord(0, $parent['table'], $parent['uid']);
1066
				$parentLanguageField = $GLOBALS['TCA'][$parent['table']]['ctrl']['languageField'];
1067
				$childLanguageField = $GLOBALS['TCA'][$current['table']]['ctrl']['languageField'];
1068
				if ($parentRecord[$languageField]>0) {
1069
					$record[$childLanguageField] = $parentRecord[$languageField];
1070
				}
1071
			}
967 1072

  
968 1073
			// dynamically import an existing record (this could be a call from a select box)
969 1074
		} else {
......
1018 1123
				)
1019 1124
			);
1020 1125
		}
1021

  
1022
			// Add data that would have been added at the top of a regular TCEforms call:
1023
		if ($headTags = $this->getHeadTags()) {
1024
			$jsonArray['headData'] = $headTags;
1025
		}
1026
			// Add the JavaScript data that would have been added at the bottom of a regular TCEforms call:
1027
		$jsonArray['scriptCall'][] = $this->fObj->JSbottom($this->fObj->formName, true);
1028
			// if script.aculo.us Sortable is used, update the Observer to know the the record
1029
		if ($config['appearance']['useSortable'])
1030
			$jsonArray['scriptCall'][] = "inline.createDragAndDropSorting('".$this->inlineNames['object']."_records');";
1031
			// if TCEforms has some JavaScript code to be executed, just do it
1032
		if ($this->fObj->extJSCODE)
1033
			$jsonArray['scriptCall'][] = $this->fObj->extJSCODE;
1126
		$this->getCommonScriptCalls($jsonArray, $config);
1034 1127
			// tell the browser to scroll to the newly created record
1035 1128
		$jsonArray['scriptCall'][] = "Element.scrollTo('".$objectId."_div');";
1036 1129
			// fade out and fade in the new record in the browser view to catch the user's eye
......
1045 1138

  
1046 1139

  
1047 1140
	/**
1141
	 * Handle AJAX calls to localize all records of a parent, localize a single record or to synchronize with the original language parent.
1142
	 *
1143
	 * @param	string		$domObjectId: The calling object in hierarchy, that requested a new record.
1144
	 * @param	mixed		$type: Defines the type 'localize' or 'synchronize' (string) or a single uid to be localized (integer)
1145
	 * @return	array		An array to be used for JSON
1146
	 */
1147
	protected function synchronizeLocalizeRecords($domObjectId, $type) {
1148
		$jsonArray = false;
1149
		if (t3lib_div::inList('localize,synchronize', $type) || t3lib_div::testInt($type)) {
1150
				// The current level:
1151
			$current = $this->inlineStructure['unstable'];
1152
				// The parent level:
1153
			$parent = $this->getStructureLevel(-1);
1154
			$parentRecord = $this->getRecord(0, $parent['table'], $parent['uid']);
1155

  
1156
			$cmd = array();
1157
			$cmd[$parent['table']][$parent['uid']]['inlineLocalizeSynchronize'] = $parent['field'].','.$type;
1158

  
1159
			/* @var t3lib_TCEmain */
1160
			$tce = t3lib_div::makeInstance('t3lib_TCEmain');
1161
			$tce->stripslashes_values = false;
1162
			$tce->start(array(), $cmd);
1163
			$tce->process_cmdmap();
1164
			$newItemList = $tce->registerDBList[$parent['table']][$parent['uid']][$parent['field']];
1165
			unset($tce);
1166

  
1167
			$jsonArray = $this->getExecuteChangesJsonArray($parentRecord[$parent['field']], $newItemList);
1168
			$this->getCommonScriptCalls($jsonArray, $parent['config']);
1169
		}
1170
		return $jsonArray;
1171
	}
1172

  
1173

  
1174
	/**
1175
	 * Generates a JSON array which executes the changes and thus updates the forms view.
1176
	 *
1177
	 * @param	string		$oldItemList: List of related child reocrds before changes were made (old)
1178
	 * @param	string		$newItemList: List of related child records after changes where made (new)
1179
	 * @return	array		An array to be used for JSON
1180
	 */
1181
	protected function getExecuteChangesJsonArray($oldItemList, $newItemList) {
1182
		$parent = $this->getStructureLevel(-1);
1183
		$current = $this->inlineStructure['unstable'];
1184

  
1185
		$jsonArray = array('scriptCall' => array());
1186
		$jsonArrayScriptCall =& $jsonArray['scriptCall'];
1187

  
1188
		$nameObject = $this->inlineNames['object'];
1189
		$nameObjectForeignTable = $nameObject.'['.$current['table'].']';
1190
			// Get the name of the field pointing to the original record:
1191
		$transOrigPointerField = $GLOBALS['TCA'][$current['table']]['ctrl']['transOrigPointerField'];
1192
			// Get the name of the field used as foreign selector (if any): 
1193
		$foreignSelector = (isset($parent['config']['foreign_selector']) && $parent['config']['foreign_selector'] ? $parent['config']['foreign_selector'] : false);
1194
			// Convert lists to array with uids of child records:
1195
		$oldItems = $this->getRelatedRecordsUidArray($oldItemList); 
1196
		$newItems = $this->getRelatedRecordsUidArray($newItemList);
1197
			// Determine the items that were localized or localized:
1198
		$removedItems = array_diff($oldItems, $newItems);
1199
		$localizedItems = array_diff($newItems, $oldItems);
1200
			// Set the items that should be removed in the forms view:
1201
		foreach ($removedItems as $item) {
1202
			$jsonArrayScriptCall[] = "inline.deleteRecord('".$nameObjectForeignTable.'['.$item.']'."', {forceDirectRemoval: true});";
1203
		}
1204
			// Set the items that should be added in the forms view:
1205
		foreach ($localizedItems as $item) {
1206
			$row = $this->getRecord($this->inlineFirstPid, $current['table'], $item);
1207
			$selectedValue = ($foreignSelector ? "'".$row[$foreignSelector]."'" : 'null');
1208
			$data.= $this->renderForeignRecord($parent['uid'], $row, $parent['config']);
1209
			$jsonArrayScriptCall[] = "inline.memorizeAddRecord('$nameObjectForeignTable', '".$item."', null, $selectedValue);";
1210
				// Remove possible virtual records in the form which showed that a child records could be localized:
1211
			if (isset($row[$transOrigPointerField]) && $row[$transOrigPointerField]) {
1212
				$jsonArrayScriptCall[] = "inline.fadeAndRemove('".$nameObjectForeignTable.'['.$row[$transOrigPointerField].']_div'."');";
1213
			}
1214
		}
1215
		if ($data) {
1216
			$data = $GLOBALS['LANG']->csConvObj->utf8_encode($data, $GLOBALS['LANG']->charSet);
1217
			$jsonArray['data'] = $data;
1218
			array_unshift(
1219
				$jsonArrayScriptCall,
1220
				"inline.domAddNewRecord('bottom', '".$nameObject."_records', '$nameObjectForeignTable', json.data);"
1221
			);
1222
		}
1223

  
1224
		return $jsonArray;
1225
	}
1226

  
1227

  
1228
	/**
1048 1229
	 * Save the expanded/collapsed state of a child record in the BE_USER->uc.
1049 1230
	 *
1050 1231
	 * @param	string		$domObjectId: The calling object in hierarchy, that requested a new record.
......
1095 1276

  
1096 1277
	/**
1097 1278
	 * Get the related records of the embedding item, this could be 1:n, m:n.
1279
	 * Returns an associative array with the keys records and count. 'count' contains only real existing records on the current parent record.
1098 1280
	 *
1099 1281
	 * @param	string		$table: The table name of the record
1100 1282
	 * @param	string		$field: The field name which this element is supposed to edit
1101 1283
	 * @param	array		$row: The record data array where the value(s) for the field can be found
1102 1284
	 * @param	array		$PA: An array with additional configuration options.
1103 1285
	 * @param	array		$config: (Redundant) content of $PA['fieldConf']['config'] (for convenience)
1104
	 * @return	array		The records related to the parent item
1286
	 * @return	array		The records related to the parent item as associative array.
1105 1287
	 */
1106
	function getRelatedRecords($table,$field,$row,&$PA,$config) {
1288
	function getRelatedRecords($table, $field, $row, &$PA, $config) {
1107 1289
		$records = array();
1290
		$pid = $row['pid'];
1291
		$elements = $PA['itemFormElValue'];
1292
		$foreignTable = $config['foreign_table'];
1108 1293

  
1109
			// Creating the label for the "No Matching Value" entry.
1110
		$nMV_label = isset($PA['fieldTSConfig']['noMatchingValue_label']) ? $this->fObj->sL($PA['fieldTSConfig']['noMatchingValue_label']) : '[ '.$this->fObj->getLL('l_noMatchingValue').' ]';
1294
		$localizationMode = t3lib_BEfunc::getInlineLocalizationMode($table, $config);
1111 1295

  
1112
			// Register the required number of elements:
1113
		# $this->fObj->requiredElements[$PA['itemFormElName']] = array($minitems,$maxitems,'imgName'=>$table.'_'.$row['uid'].'_'.$field);
1296
		if ($localizationMode!=false) {
1297
			$language = intval($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]);
1298
			$transOrigPointer = intval($row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]);
1299
			if ($language>0 && $transOrigPointer) {
1300
					// Localization in mode 'keep', isn't a real localization, but keeps the children of the original parent record:
1301
				if ($localizationMode=='keep') {
1302
					$transOrigRec = $this->getRecord(0, $table, $transOrigPointer);
1303
					$elements = $transOrigRec[$field];
1304
					$pid = $transOrigRec['pid'];
1305
					// Localization in modes 'select', 'all' or 'sync' offer a dynamic localization and synchronization with the original language record:
1306
				} elseif ($localizationMode=='select') {
1307
					$transOrigRec = $this->getRecord(0, $table, $transOrigPointer);
1308
					$pid = $transOrigRec['pid'];
1309
					$recordsOriginal = $this->getRelatedRecordsArray($pid, $foreignTable, $transOrigRec[$field]);
1310
				}
1311
			}
1312
		}
1114 1313

  
1314
		$records = $this->getRelatedRecordsArray($pid, $foreignTable, $elements);
1315
		$relatedRecords = array('records' => $records, 'count' => count($records));
1316

  
1317
			// Merge original language with current localization and show differences:
1318
		if (is_array($recordsOriginal)) {
1319
			$options = array(
1320
				'showPossible' => (isset($config['appearance']['showPossibleLocalizationRecords']) && $config['appearance']['showPossibleLocalizationRecords']),
1321
				'showRemoved' => (isset($config['appearance']['showRemovedLocalizationRecords']) && $config['appearance']['showRemovedLocalizationRecords']),
1322
			);
1323
			if ($options['showPossible'] || $options['showRemoved']) {
1324
				$relatedRecords['records'] = $this->getLocalizationDifferences($foreignTable, $options, $recordsOriginal, $records); 
1325
			}
1326
		}
1327

  
1328
		return $relatedRecords;
1329
	}
1330

  
1331

  
1332
	/**
1333
	 * Gets the related records of the embedding item, this could be 1:n, m:n.
1334
	 *
1335
	 * @param	integer		$pid: The pid of the parent record
1336
	 * @param	string		$table: The table name of the record
1337
	 * @param	string		$itemList: The list of related child records
1338
	 * @return	array		The records related to the parent item 
1339
	 */
1340
	protected function getRelatedRecordsArray($pid, $table, $itemList) {
1341
		$records = array();
1342
		$itemArray = $this->getRelatedRecordsUidArray($itemList);
1115 1343
			// Perform modification of the selected items array:
1116
		$itemArray = t3lib_div::trimExplode(',',$PA['itemFormElValue'],1);
1117
		foreach($itemArray as $tk => $tv) {
1118
			$tvP = explode('|',$tv,2);
1119
				// get the records for this uid using t3lib_transferdata
1120
			$records[] = $this->getRecord($row['pid'], $config['foreign_table'], $tvP[0]);
1344
		foreach($itemArray as $uid) {
1345
				// Get the records for this uid using t3lib_transferdata:
1346
			$records[$uid] = $this->getRecord($pid, $table, $uid);
1121 1347
		}
1348
		return $records;
1349
	}
1122 1350

  
1351

  
1352
	/**
1353
	 * Gets an array with the uids of related records out of a list of items.
1354
	 * This list could contain more information than required. This methods just
1355
	 * extracts the uids.
1356
	 *
1357
	 * @param	string		$itemList: The list of related child records
1358
	 * @return	array		An array with uids 
1359
	 */
1360
	protected function getRelatedRecordsUidArray($itemList) {
1361
		$itemArray = t3lib_div::trimExplode(',', $itemList, 1);
1362
			// Perform modification of the selected items array:
1363
		foreach($itemArray as $key => &$value) {
1364
			$parts = explode('|', $value, 2);
1365
			$value = $parts[0];
1366
		}
1367
		return $itemArray;
1368
	}
1369

  
1370

  
1371
	/**
1372
	 * Gets the difference between current localized structure and the original language structure.
1373
	 * If there are records which once were localized but don't exist in the original version anymore, the record row is marked with '__remove'.
1374
	 * If there are records which can be localized and exist only in the original version, the record row is marked with '__create' and '__virtual'.
1375
	 *
1376
	 * @param	string		$table: The table name of the parent records
1377
	 * @param	array		$options: Options defining what kind of records to display
1378
	 * @param	array		$recordsOriginal: The uids of the child records of the original language
1379
	 * @param	array		$recordsLocalization: The uids of the child records of the current localization
1380
	 * @return	array		Merged array of uids of the child records of both versions
1381
	 */
1382
	protected function getLocalizationDifferences($table, array $options, array $recordsOriginal, array $recordsLocalization) {
1383
		$records = array();
1384
		$transOrigPointerField = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'];
1385
			// Compare original to localized version of the records:
1386
		foreach ($recordsLocalization as $uid => $row) {
1387
				// If the record points to a original translation which doesn't exist anymore, it could be removed: 
1388
			if (isset($row[$transOrigPointerField]) && $row[$transOrigPointerField]>0) {
1389
				$transOrigPointer = $row[$transOrigPointerField];
1390
				if (isset($recordsOriginal[$transOrigPointer])) {
1391
					unset($recordsOriginal[$transOrigPointer]);
1392
				} elseif ($options['showRemoved']) {
1393
					$row['__remove'] = true;
1394
				}
1395
			}
1396
			$records[$uid] = $row;
1397
		}
1398
			// Process the remaining records in the original unlocalized parent:
1399
		if ($options['showPossible']) {
1400
			foreach ($recordsOriginal as $uid => $row) {
1401
				$row['__create'] = true;
1402
				$row['__virtual'] = true;
1403
				$records[$uid] = $row;
1404
			}
1405
		}
1123 1406
		return $records;
1124 1407
	}
1125 1408

  
......
1145 1428
		$foreignConfig = $this->getPossibleRecordsSelectorConfig($conf, $foreign_check);
1146 1429
		$PA = $foreignConfig['PA'];
1147 1430
		$config = $PA['fieldConf']['config'];
1148
		
1431

  
1149 1432
		if ($foreignConfig['type'] == 'select') {
1150 1433
				// Getting the selector box items from the system
1151 1434
			$selItems = $this->fObj->addSelectOptionsToItemArray($this->fObj->initItemArray($PA['fieldConf']),$PA['fieldConf'],$this->fObj->setTSconfig($table,$row),$field);
1152 1435
			if ($config['itemsProcFunc']) $selItems = $this->fObj->procItems($selItems,$PA['fieldTSConfig']['itemsProcFunc.'],$config,$table,$row,$field);
1153
	
1436

  
1154 1437
				// Possibly remove some items:
1155 1438
			$removeItems = t3lib_div::trimExplode(',',$PA['fieldTSConfig']['removeItems'],1);
1156 1439
			foreach($selItems as $tk => $p)	{
1157
	
1440

  
1158 1441
					// Checking languages and authMode:
1159 1442
				$languageDeny = $tcaTableCtrl['languageField'] && !strcmp($tcaTableCtrl['languageField'], $field) && !$GLOBALS['BE_USER']->checkLanguageAccess($p[1]);
1160 1443
				$authModeDeny = $config['form_type']=='select' && $config['authMode'] && !$GLOBALS['BE_USER']->checkAuthMode($table,$field,$p[1],$config['authMode']);
......
1163 1446
				} elseif (isset($PA['fieldTSConfig']['altLabels.'][$p[1]])) {
1164 1447
					$selItems[$tk][0]=$this->fObj->sL($PA['fieldTSConfig']['altLabels.'][$p[1]]);
1165 1448
				}
1166
	
1449

  
1167 1450
					// Removing doktypes with no access:
1168 1451
				if ($table.'.'.$field == 'pages.doktype')	{
1169 1452
					if (!($GLOBALS['BE_USER']->isAdmin() || t3lib_div::inList($GLOBALS['BE_USER']->groupData['pagetypes_select'],$p[1])))	{
......
1189 1472
	function getUniqueIds($records, $conf=array(), $splitValue=false) {
1190 1473
		$uniqueIds = array();
1191 1474

  
1192
		if ($conf['foreign_unique'] && count($records)) {
1475
		if (isset($conf['foreign_unique']) && $conf['foreign_unique'] && count($records)) {
1193 1476
			foreach ($records as $rec) {
1194
				$value = $rec[$conf['foreign_unique']];
1195
					// Split the value and extract the table and uid:
1196
				if ($splitValue) {
1197
					$valueParts = t3lib_div::trimExplode('|', $value);
1198
					$itemParts = explode('_', $valueParts[0]);
1199
					$value = array(
1200
						'uid' => array_pop($itemParts),
1201
						'table' => implode('_', $itemParts)
1202
					);
1477
					// Skip virtual records (e.g. shown in localization mode):
1478
				if (!isset($rec['__virtual']) || !$rec['__virtual']) {
1479
					$value = $rec[$conf['foreign_unique']];
1480
						// Split the value and extract the table and uid:
1481
					if ($splitValue) {
1482
						$valueParts = t3lib_div::trimExplode('|', $value);
1483
						$itemParts = explode('_', $valueParts[0]);
1484
						$value = array(
1485
							'uid' => array_pop($itemParts),
1486
							'table' => implode('_', $itemParts)
1487
						);
1488
					}
1489
					$uniqueIds[$rec['uid']] = $value;
1203 1490
				}
1204
				$uniqueIds[$rec['uid']] = $value;
1205 1491
			}
1206 1492
		}
1207 1493

  
......
1271 1557
			'uid' => $uid,
1272 1558
			'field' => $field,
1273 1559
			'config' => $config,
1560
			'localizationMode' => t3lib_BEfunc::getInlineLocalizationMode($table, $config),
1274 1561
		);
1275 1562
		$this->updateStructureNames();
1276 1563
	}
......
1377 1664
	 *  - 'unstable': Containting partly filled data (e.g. only table and possibly field)
1378 1665
	 *
1379 1666
	 * @param	string		$domObjectId: The DOM object-id
1380
	 * @param	boolean		$loadConfig: Load the TCA configuration for that level
1667
	 * @param	boolean		$loadConfig: Load the TCA configuration for that level (default: true)
1381 1668
	 * @return	void
1382 1669
	 */
1383
	function parseStructureString($string, $loadConfig = false) {
1670
	function parseStructureString($string, $loadConfig=true) {
1384 1671
		$unstable = array();
1385 1672
		$vector = array('table', 'uid', 'field');
1386 1673
		$pattern = '/^'.$this->prependNaming.'\[(.+?)\]\[(.+)\]$/';
......
1404 1691
						if (!$TSconfig['disabled']) {
1405 1692
							$unstable['config'] = $this->fObj->overrideFieldConf($unstable['config'], $TSconfig);
1406 1693
						}
1694
						$unstable['localizationMode'] = t3lib_BEfunc::getInlineLocalizationMode($unstable['table'], $unstable['config']);
1407 1695
					}
1408 1696
					$this->inlineStructure['stable'][] = $unstable;
1409 1697
					$unstable = array();
......
1427 1715
	 * Does some checks on the TCA configuration of the inline field to render.
1428 1716
	 *
1429 1717
	 * @param	array		$config: Reference to the TCA field configuration
1718
	 * @param	string		$table: The table name of the record
1719
	 * @param	string		$field: The field name which this element is supposed to edit
1720
	 * @param	array		$row: The record data array of the parent
1430 1721
	 * @return	boolean		If critical configuration errors were found, false is returned
1431 1722
	 */
1432 1723
	function checkConfiguration(&$config) {
......
1437 1728
			return false;
1438 1729
		}
1439 1730
			// Init appearance if not set:
1440
		if (!is_array($config['appearance'])) {
1731
		if (!isset($config['appearance']) || !is_array($config['appearance'])) {
1441 1732
			$config['appearance'] = array();
1442 1733
		}
1734
			// 'newRecordLinkPosition' is deprecated since TYPO3 4.2.0-beta1, this is for backward compatibility: 
1735
		if (!isset($config['appearance']['levelLinksPosition']) && isset($config['appearance']['newRecordLinkPosition']) && $config['appearance']['newRecordLinkPosition']) {
1736
			$config['appearance']['levelLinksPosition'] = $config['appearance']['newRecordLinkPosition'];
1737
		}
1443 1738
			// Set the position/appearance of the "Create new record" link:
1444
		if ($config['foreign_selector'] && !$config['appearance']['useCombination']) {
1445
			$config['appearance']['newRecordLinkPosition'] = 'none';
1446
		} elseif (!in_array($config['appearance']['newRecordLinkPosition'], array('top', 'bottom', 'both', 'none'))) {
1447
			$config['appearance']['newRecordLinkPosition'] = 'top';
1739
		if (isset($config['foreign_selector']) && $config['foreign_selector'] && (!isset($config['appearance']['useCombination']) || !$config['appearance']['useCombination'])) {
1740
			$config['appearance']['levelLinksPosition'] = 'none';
1741
		} elseif (!isset($config['appearance']['levelLinksPosition']) || !in_array($config['appearance']['levelLinksPosition'], array('top', 'bottom', 'both', 'none'))) {
1742
			$config['appearance']['levelLinksPosition'] = 'top';
1448 1743
		}
1449 1744

  
1450 1745
		return true;
......
1756 2051
		$type = false;
1757 2052
		$table = false;
1758 2053
		$selector = false;
1759
		
2054

  
1760 2055
		if ($field) {
1761 2056
			$PA = array();
1762 2057
			$PA['fieldConf'] = $GLOBALS['TCA'][$foreign_table]['columns'][$field];
......
1772 2067
				$selector = $type;
1773 2068
			}
1774 2069
		}
1775
		
2070

  
1776 2071
		return array(
1777 2072
			'PA' => $PA,
1778 2073
			'type' => $type,
......
1780 2075
			'selector' => $selector,
1781 2076
		);
1782 2077
	}
1783
	
1784 2078

  
2079

  
1785 2080
	/**
1786 2081
	 * Determine the type of a record selector, e.g. select or group/db.
1787 2082
	 *
......
1797 2092
		}
1798 2093
		return $type;
1799 2094
	}
1800
	
1801
	
2095

  
2096

  
1802 2097
	/**
1803 2098
	 * Check, if a field should be skipped, that was defined to be handled as foreign_field or foreign_sortby of
1804 2099
	 * the parent record of the "inline"-type - if so, we have to skip this field - the rendering is done via "inline" as hidden field
......
1963 2258

  
1964 2259
		return $headTags;
1965 2260
	}
2261

  
2262

  
2263
	/**
2264
	 * Wraps a text with an anchor and returns the HTML representation.
2265
	 *
2266
	 * @param	string		$text: The text to be wrapped by an anchor
2267
	 * @param	string		$link: The link to be used in the anchor 
2268
	 * @param	array		$attributes: Array of attributes to be used in the anchor
2269
	 * @return	string		The wrapped texted as HTML representation
2270
	 */
2271
	protected function wrapWithAnchor($text, $link, $attributes=array()) {
2272
		$link = trim($link);
2273
		$result = '<a href="'.($link ? $link : '#').'"';
2274
		foreach ($attributes as $key => $value) {
2275
			$result.= ' '.$key.'="'.htmlspecialchars(trim($value)).'"';
2276
		}
2277
		$result.= '>'.$text.'</a>';
2278
		return $result;
2279
	}
1966 2280
}
1967 2281

  
1968 2282

  
t3lib/class.t3lib_tcemain.php (Revision 3042)
2 2
/***************************************************************
3 3
*  Copyright notice
4 4
*
5
*  (c) 1999-2007 Kasper Skaarhoj (kasperYYYY@typo3.com)
5
*  (c) 1999-2008 Kasper Skaarhoj (kasperYYYY@typo3.com)
6 6
*  All rights reserved
7 7
*
8 8
*  This script is part of the TYPO3 project. The TYPO3 project is
......
1748 1748
				$arrValue = t3lib_div::array_merge_recursive_overrule($currentValueArray,$arrValue);
1749 1749
				$xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
1750 1750
			}
1751
		
1751

  
1752 1752
				// Action commands (sorting order and removals of elements)
1753 1753
			$actionCMDs = t3lib_div::_GP('_ACTION_FLEX_FORMdata');
1754 1754
			if (is_array($actionCMDs[$table][$id][$field]['data']))	{
......
1825 1825
	 * @return	array		Modified $res array
1826 1826
	 */
1827 1827
	function checkValue_inline($res,$value,$tcaFieldConf,$PP,$field)	{
1828
		list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
1828
		list($table, $id, $curValue, $status, $realPid, $recFID) = $PP;
1829 1829

  
1830 1830
		if (!$tcaFieldConf['foreign_table'])	{
1831 1831
			return false;	// Fatal error, inline fields should always have a foreign_table defined
......
1843 1843
		if(strpos($value, 'NEW') !== false || !t3lib_div::testInt($id)) {
1844 1844
			$this->remapStackRecords[$table][$id] = array('remapStackIndex' => count($this->remapStack));
1845 1845
			$this->remapStack[] = array(
1846
				'func' => 'checkValue_group_select_processDBdata',
1847
				'args' => array($valueArray,$tcaFieldConf,$id,$status,'inline',$table),
1848
				'pos' => array('valueArray' => 0, 'tcaFieldConf' => 1, 'id' => 2, 'table' => 5),
1846
				'func' => 'checkValue_inline_processDBdata',
1847
				'args' => array($valueArray, $tcaFieldConf, $id, $status, $table, $field),
1848
				'pos' => array('valueArray' => 0, 'tcaFieldConf' => 1, 'id' => 2, 'table' => 4),
1849 1849
				'field' => $field
1850 1850
			);
1851 1851
			unset($res['value']);
1852 1852
		} elseif($value || t3lib_div::testInt($id)) {
1853
			$newValueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'inline', $table);
1854
				// Checking that the number of items is correct
1855
			$newVal = $this->checkValue_checkMax($tcaFieldConf, $newValueArray);
1856
			$res['value'] = implode(',',$newVal);
1853
			$res['value'] = $this->checkValue_inline_processDBdata($valueArray, $tcaFieldConf, $id, $status, $table, $field);
1857 1854
		}
1858 1855

  
1859 1856
		return $res;
......
2068 2065
				$this->dbAnalysisStore[] = array($dbAnalysis,$tcaFieldConf['MM'],$id,$prep,$currentTable);	// This will be traversed later to execute the actions
2069 2066
			}
2070 2067
			$valueArray = $dbAnalysis->countItems();
2071
		} elseif ($type == 'inline') {
2072
			if ($tcaFieldConf['foreign_field']) {
2073
					// if the record was imported, sorting was also imported, so skip this
2074
				$skipSorting = $this->callFromImpExp ? true : false;
2075
					// update record in intermediate table (sorting & pointer uid to parent record)
2076
				$dbAnalysis->writeForeignField($tcaFieldConf, $id, 0, $skipSorting);
2077
				$valueArray = $dbAnalysis->countItems();
2078
			} else {
2079
				$valueArray = $dbAnalysis->getValueArray($prep);
2080
				if ($prep) {
2081
						// @TODO: Do we want to support relations to multiple tables in Comma Separated Lists?
2082
					$valueArray = $dbAnalysis->convertPosNeg($valueArray,$tcaFieldConf['foreign_table'],$tcaFieldConf['neg_foreign_table']);
2083
				}
2084
			}
2085 2068
		} else {
2086 2069
			$valueArray = $dbAnalysis->getValueArray($prep);
2087 2070
			if ($type=='select' && $prep)	{
......
2312 2295
		}
2313 2296
	}
2314 2297

  
2298
	/**
2299
	 * Returns data for inline fields.
2300
	 *
2301
	 * @param	array		Current value array
2302
	 * @param	array		TCA field config
2303
	 * @param	integer		Record id
2304
	 * @param	string		Status string ('update' or 'new')
2305
	 * @param	string		Table name, needs to be passed to t3lib_loadDBGroup
2306
	 * @param	string		The current field the values are modified for
2307
	 * @return	string		Modified values
2308
	 */
2309
	protected function checkValue_inline_processDBdata($valueArray, $tcaFieldConf, $id, $status, $table, $field)	{
2310
		$newValue = '';
2311
		$foreignTable = $tcaFieldConf['foreign_table'];
2315 2312

  
2313
		/*
2314
		 * Fetch the related child records by using t3lib_loadDBGroup:
2315
		 * @var $dbAnalysis t3lib_loadDBGroup
2316
		 */
2317
		$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
2318
		$dbAnalysis->start(implode(',', $valueArray), $foreignTable, '', 0, $table, $tcaFieldConf);
2319
			// If the localizazionMode is set to 'keep', the children for the localized parent are kept as in the original untranslated record:
2320
		$localizationMode = t3lib_BEfunc::getInlineLocalizationMode($table, $tcaFieldConf);
2321
		if ($localizationMode=='keep' && $status=='update') {
2322
				// Fetch the current record and determine the original record:
2323
			$row = t3lib_BEfunc::getRecordWSOL($table, $id);
2324
			if (is_array($row)) {
2325
				$language = intval($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]);
2326
				$transOrigPointer = intval($row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]);
2327
					// If language is set (e.g. 1) and also transOrigPointer (e.g. 123), use transOrigPointer as uid:
2328
				if ($language>0 && $transOrigPointer) {
2329
					$id = $transOrigPointer;
2330
						// If we're in active localizationMode 'keep', prevent from writing data to the field of the parent record:
2331
						// (on removing the localized parent, the original (untranslated) children would then also be removed)
2332
					$keepTranslation = true;
2333
				}
2334
			}
2335
		}
2336
			// IRRE with a pointer field (database normalization): 
2337
		if ($tcaFieldConf['foreign_field']) {
2338
				// if the record was imported, sorting was also imported, so skip this
2339
			$skipSorting = ($this->callFromImpExp ? true : false);
2340
				// update record in intermediate table (sorting & pointer uid to parent record)
2341
			$dbAnalysis->writeForeignField($tcaFieldConf, $id, 0, $skipSorting);
2342
			$newValue = ($keepTranslation ? 0 : $dbAnalysis->countItems(false));
2343
			// IRRE with comma separated values:
2344
		} else {
2345
			$valueArray = $dbAnalysis->getValueArray();
2346
				// Checking that the number of items is correct:
2347
			$valueArray = $this->checkValue_checkMax($tcaFieldConf, $valueArray);
2348
				// If a valid translation of the 'keep' mode is active, update relations in the original(!) record:
2349
			if ($keepTranslation) {
2350
				$this->updateDB($table, $transOrigPointer, array($field => implode(',', $valueArray)));
2351
			} else {
2352
				$newValue = implode(',', $valueArray);
2353
			}
2354
		}
2316 2355

  
2356
		return $newValue;
2357
	}
2317 2358

  
2318 2359

  
2319 2360

  
......
2328 2369

  
2329 2370

  
2330 2371

  
2372

  
2331 2373
	/*********************************************
2332 2374
	 *
2333 2375
	 * PROCESSING COMMANDS
......
2407 2449
							case 'localize':
2408 2450
								$this->localize($table,$id,$value);
2409 2451
							break;
2452
							case 'inlineLocalizeSynchronize':
2453
								$this->inlineLocalizeSynchronize($table, $id, $value);
2454
							break;
2410 2455
							case 'version':
2411 2456
								switch ((string)$value['action'])	{
2412 2457
									case 'new':
......
2536 2581
	 * @param	boolean		$first is a flag set, if the record copied is NOT a 'slave' to another record copied. That is, if this record was asked to be copied in the cmd-array
2537 2582
	 * @param	array		Associative array with field/value pairs to override directly. Notice; Fields must exist in the table record and NOT be among excluded fields!
2538 2583
	 * @param	string		Commalist of fields to exclude from the copy process (might get default values)
2584
	 * @param	integer		Language ID (from sys_language table)
2539 2585
	 * @return	integer		ID of new record, if any
2540 2586
	 */
2541
	function copyRecord($table,$uid,$destPid,$first=0,$overrideValues=array(),$excludeFields='')	{
2587
	function copyRecord($table, $uid, $destPid, $first=0, $overrideValues=array(), $excludeFields='', $language=0) {
2542 2588
		global $TCA;
2543 2589

  
2544 2590
		$uid = $origUid = intval($uid);
......
2607 2653
									$value = $this->getCopyHeader($table,$this->resolvePid($table,$destPid),$field,$this->clearPrefixFromValue($table,$value),0);
2608 2654
								}
2609 2655
									// Processing based on the TCA config field type (files, references, flexforms...)
2610
								$value = $this->copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf,$tscPID);
2656
								$value = $this->copyRecord_procBasedOnFieldType($table, $uid, $field, $value, $row, $conf, $tscPID, $language);
2611 2657
							}
2612 2658

  
2613 2659
								// Add value to array.
......
2895 2941
	 * @param	array		Record array
2896 2942
	 * @param	array		TCA field configuration
2897 2943
	 * @param	integer		Real page id (pid) the record is copied to
2944
	 * @param	integer		Language ID (from sys_language table)
2898 2945
	 * @return	mixed		Processed value. Normally a string/integer, but can be an array for flexforms!
2899 2946
	 * @access private
2900 2947
	 * @see copyRecord()
2901 2948
	 */
2902
	function copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf,$realDestPid) {
2949
	function copyRecord_procBasedOnFieldType($table, $uid, $field, $value, $row, $conf, $realDestPid, $language=0) {
2903 2950
		global $TCA;
2904 2951

  
2905 2952
			// Process references and files, currently that means only the files, prepending absolute paths (so the TCEmain engine will detect the file as new and one that should be made into a copy)
......
2910 2957
		if ($this->isReferenceField($conf) || $inlineSubType == 'mm')	{
2911 2958
			$allowedTables = $conf['type']=='group' ? $conf['allowed'] : $conf['foreign_table'].','.$conf['neg_foreign_table'];
2912 2959
			$prependName = $conf['type']=='group' ? $conf['prepend_tname'] : $conf['neg_foreign_table'];
2913
			if ($conf['MM'])	{
2960
			$localizeReferences = (isset($conf['foreign_table']) && t3lib_BEfunc::isTableLocalizable($conf['foreign_table']) && isset($conf['localizeReferencesAtParentLocalization']) && $conf['localizeReferencesAtParentLocalization']);
2961
			if ($conf['MM'] || $language>0 && $localizeReferences) {
2914 2962
				$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
2915 2963
				/* @var $dbAnalysis t3lib_loadDBGroup */
2916
				$dbAnalysis->start('', $allowedTables, $conf['MM'], $uid, $table, $conf);
2964
				$dbAnalysis->start($value, $allowedTables, $conf['MM'], $uid, $table, $conf);
2965
				if (!$conf['MM']) {
2966
						// Localize referenced records of select fields:
2967
					foreach ($dbAnalysis->itemArray as $index => $item) {
2968
							// Since select fields can reference many records, check whether there's already a localization:
2969
						$recordLocalization = t3lib_BEfunc::getRecordLocalization($item['table'], $item['id'], $language);
2970
						if (!$recordLocalization) {
2971
							$dbAnalysis->itemArray[$index]['id'] = $this->localize($item['table'], $item['id'], $language);
2972
						} else {
2973
							$dbAnalysis->itemArray[$index]['id'] = $recordLocalization[0]['uid'];
2974
						}
2975
					}
2976
				}
2917 2977
				$value = implode(',',$dbAnalysis->getValueArray($prependName));
2918 2978
			}
2919 2979
			if ($value)	{	// Setting the value in this array will notify the remapListedDBRecords() function that this field MAY need references to be corrected
......
2922 2982

  
2923 2983
			// If another inline subtype is used (comma-separated-values or the foreign_field property):
2924 2984
		} elseif ($inlineSubType !== false) {
2925
			$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
2926
			/* @var $dbAnalysis t3lib_loadDBGroup */
2927
			$dbAnalysis->start($value, $conf['foreign_table'], '', $uid, $table, $conf);
2985
				// Get the localization mode for the current (parent) record (keep|select|all):
2986
			$localizazionMode = t3lib_BEfunc::getInlineLocalizationMode($table, $field);
2987
				// Localization in mode 'keep', isn't a real localization, but keeps the children of the original parent record:
2988
			if ($language>0 && $localizazionMode=='keep') {
2989
				$value = ($inlineSubType=='field' ? 0 : '');
2990
				// Execute copy or localization actions:
2991
			} else {
2992
				/*
2993
				 * Fetch the related child records by using t3lib_loadDBGroup:
2994
				 * @var $dbAnalysis t3lib_loadDBGroup
2995
				 */
2996
				$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
2997
				$dbAnalysis->start($value, $conf['foreign_table'], '', $uid, $table, $conf);
2928 2998

  
2929
				// walk through the items, copy them and remember the new id
2930
			foreach ($dbAnalysis->itemArray as $k => $v) {
2931
				if (!t3lib_div::testInt($realDestPid)) {
2932
					$newId = $this->copyRecord($v['table'], $v['id'], -$v['id']);
2933
				} elseif ($realDestPid == -1) {
2934
					$newId = $this->versionizeRecord($v['table'], $v['id'], 'Auto-created for WS #'.$this->BE_USER->workspace);
2935
				} else {
2936
					$newId = $this->copyRecord_raw($v['table'], $v['id'], $realDestPid);
2937
				}
2999
					// Walk through the items, copy them and remember the new id:
3000
				foreach ($dbAnalysis->itemArray as $k => $v) {
3001
						// If language is set, this isn't a copy action but a localization of our parent/ancestor:
3002
					if ($language>0) {
3003
							// If children should be localized when the parent gets localized the first time, just do it:
3004
						if ($localizazionMode!=false && isset($conf['behaviour']['localizeChildrenAtParentLocalization']) && $conf['behaviour']['localizeChildrenAtParentLocalization']) {
3005
							$newId = $this->localize($v['table'], $v['id'], $language);
3006
						}
3007
						// If no language it set, this is a regular copy action:
3008
					} else {
3009
						if (!t3lib_div::testInt($realDestPid)) {
3010
							$newId = $this->copyRecord($v['table'], $v['id'], -$v['id']);
3011
						} elseif ($realDestPid == -1) {
3012
							$newId = $this->versionizeRecord($v['table'], $v['id'], 'Auto-created for WS #'.$this->BE_USER->workspace);
3013
						} else {
3014
							$newId = $this->copyRecord_raw($v['table'], $v['id'], $realDestPid);
3015
						}
3016
					}
2938 3017

  
2939
					// If the current field is set on a page record, update the pid of related child records:
2940
				if ($table == 'pages') {
2941
					$this->registerDBPids[$v['table']][$v['id']] = $uid;
2942
					// If the current field has ancestors that have a field on a page record, update the pid of related child records:
2943
				} elseif (isset($this->registerDBPids[$table][$uid])) {
2944
					$this->registerDBPids[$v['table']][$v['id']] = $this->registerDBPids[$table][$uid];
3018
						// If the current field is set on a page record, update the pid of related child records:
3019
					if ($table == 'pages') {
3020
						$this->registerDBPids[$v['table']][$v['id']] = $uid;
3021
						// If the current field has ancestors that have a field on a page record, update the pid of related child records:
3022
					} elseif (isset($this->registerDBPids[$table][$uid])) {
3023
						$this->registerDBPids[$v['table']][$v['id']] = $this->registerDBPids[$table][$uid];
3024
					}
3025

  
3026
					$dbAnalysis->itemArray[$k]['id'] = $newId;
2945 3027
				}
2946 3028

  
2947
				$dbAnalysis->itemArray[$k]['id'] = $newId;
3029
					// Store the new values, we will set up the uids for the subtype later on (exception keep localization from original record):
3030
				$value = implode(',',$dbAnalysis->getValueArray());
3031
				$this->registerDBList[$table][$uid][$field] = $value;
2948 3032
			}
2949

  
2950
				// store the new values, we will set up the uids for the subtype later on
2951
			$value = implode(',',$dbAnalysis->getValueArray());
2952
			$this->registerDBList[$table][$uid][$field] = $value;
2953 3033
		}
2954 3034

  
2955 3035
			// For "flex" fieldtypes we need to traverse the structure for two reasons: If there are file references they have to be prepended with absolute paths and if there are database reference they MIGHT need to be remapped (still done in remapListedDBRecords())
......
3522 3602
	 * @param	string		Table name
3523 3603
	 * @param	integer		Record uid (to be localized)
3524 3604
	 * @param	integer		Language ID (from sys_language table)
3525
	 * @return	void
3605
	 * @return	mixed		The uid (integer) of the new translated record or false (boolean) if something went wrong
3526 3606
	 */
3527
	function localize($table,$uid,$language)	{
3607
	function localize($table, $uid, $language) {
3528 3608
		global $TCA;
3529 3609

  
3610
		$newId = false;
3530 3611
		$uid = intval($uid);
3531 3612

  
3532 3613
		if ($TCA[$table] && $uid)	{
......
3545 3626
										$Ttable = 'pages_language_overlay';
3546 3627
										t3lib_div::loadTCA($Ttable);
3547 3628
									} else {
3548
										$pass = !t3lib_BEfunc::getRecordsByField($table,$TCA[$table]['ctrl']['transOrigPointerField'],$uid,'AND pid='.intval($row['pid']).' AND '.$TCA[$table]['ctrl']['languageField'].'='.intval($langRec['uid']));
3629
										$pass = !t3lib_BEfunc::getRecordLocalization($table, $uid, $langRec['uid'], 'AND pid='.intval($row['pid']));
3549 3630
										$Ttable = $table;
3550 3631
									}
3551 3632

  
......
3583 3664
										if ($Ttable === $table)	{
3584 3665

  
3585 3666
												// Execute the copy:
3586
											$this->copyRecord($table,$uid,-$uid,1,$overrideValues,implode(',',$excludeFields));
3667
											$newId = $this->copyRecord($table, $uid, -$uid, 1, $overrideValues, implode(',', $excludeFields), $language);
3587 3668
										} else {
3588 3669

  
3589 3670
												// Create new record:
......
3601 3682
											if ($theNewSQLID)	{
3602 3683
													// If is by design that $Ttable is used and not $table! See "l10nmgr" extension. Could be debated, but this is what I chose for this "pseudo case"
3603 3684
												$this->copyMappingArray[$Ttable][$uid] = $theNewSQLID;
3685
												$newId = $theNewSQLID;
3604 3686
											}
3605 3687
										}
3606 3688
									} else $this->newlog('Localization failed; There already was a localization for this language of the record!',1);
......
3611 3693
				} else $this->newlog('Sys language UID "'.$language.'" not found valid!',1);
... This diff was truncated because it exceeds the maximum size that can be displayed.