Project

General

Profile

Feature #17500 » 0006087_v4.patch

Administrator Admin, 2008-02-03 21:00

View differences:

t3lib/config_default.php (Revision 3042)
'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.
'SC_alt_db_navframe::expandCollapse' => 'typo3/alt_db_navframe.php:SC_alt_db_navframe->ajaxExpandCollapse',
'SC_alt_file_navframe::expandCollapse' => 'typo3/alt_file_navframe.php:SC_alt_file_navframe->ajaxExpandCollapse',
't3lib_TCEforms_inline::createNewRecord' => 't3lib/class.t3lib_tceforms_inline.php:t3lib_TCEforms_inline->processAjaxRequest',
't3lib_TCEforms_inline::createNewRecord' => 't3lib/class.t3lib_tceforms_inline.php:t3lib_TCEforms_inline->processAjaxRequest',
't3lib_TCEforms_inline::synchronizeLocalizeRecords' => 't3lib/class.t3lib_tceforms_inline.php:t3lib_TCEforms_inline->processAjaxRequest',
't3lib_TCEforms_inline::setExpandedCollapsedState' => 't3lib/class.t3lib_tceforms_inline.php:t3lib_TCEforms_inline->processAjaxRequest',
'ShortcutMenu::getGroups' => 'typo3/classes/class.shortcutmenu.php:ShortcutMenu->getAjaxShortcutGroups',
'ShortcutMenu::saveShortcut' => 'typo3/classes/class.shortcutmenu.php:ShortcutMenu->setAjaxShortcut',
t3lib/class.t3lib_tceforms.php (Revision 3042)
/***************************************************************
* Copyright notice
*
* (c) 1999-2006 Kasper Skaarhoj (kasperYYYY@typo3.com)
* (c) 1999-2008 Kasper Skaarhoj (kasperYYYY@typo3.com)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
......
'check' => array('cols', 'showIfRTE'),
'select' => array('size', 'autoSizeMax', 'maxitems', 'minitems'),
'group' => array('size', 'autoSizeMax', 'max_size', 'show_thumbs', 'maxitems', 'minitems'),
'inline' => array('appearance', 'foreign_label', 'foreign_selector', 'foreign_unique', 'maxitems', 'minitems', 'size', 'autoSizeMax', 'symmetric_label'),
'inline' => array('appearance', 'behaviour', 'foreign_label', 'foreign_selector', 'foreign_unique', 'maxitems', 'minitems', 'size', 'autoSizeMax', 'symmetric_label'),
);
// Create instance of t3lib_TCEforms_inline only if this a non-IRRE-AJAX call:
......
$dLVal = t3lib_BEfunc::getProcessedValue($table,$field,$this->defaultLanguageData[$table.':'.$row['uid']][$field],0,1);
$fCfg = $GLOBALS['TCA'][$table]['columns'][$field];
if (strcmp($dLVal,'')) {
$item.='<div class="typo3-TCEforms-originalLanguageValue">'.$this->getLanguageIcon($table,$row,0).$this->previewFieldValue($dLVal,$fCfg).'&nbsp;</div>';
}
// Don't show content if it's for IRRE child records:
if (isset($fCfg['config']['type']) && $fCfg['config']['type']!='inline') {
if (strcmp($dLVal,'')) {
$item.='<div class="typo3-TCEforms-originalLanguageValue">'.$this->getLanguageIcon($table,$row,0).$this->previewFieldValue($dLVal,$fCfg).'&nbsp;</div>';
}
$prLang = $this->getAdditionalPreviewLanguages();
foreach($prLang as $prL) {
$dlVal = t3lib_BEfunc::getProcessedValue($table,$field,$this->additionalPreviewLanguageData[$table.':'.$row['uid']][$prL['uid']][$field],0,1);
$prLang = $this->getAdditionalPreviewLanguages();
foreach($prLang as $prL) {
$dlVal = t3lib_BEfunc::getProcessedValue($table,$field,$this->additionalPreviewLanguageData[$table.':'.$row['uid']][$prL['uid']][$field],0,1);
if(strcmp($dlVal, '')) {
$item.= '<div class="typo3-TCEforms-originalLanguageValue">'.$this->getLanguageIcon($table, $row, 'v'.$prL['ISOcode']).$this->previewFieldValue($dlVal, $fCfg).'&nbsp;</div>';
if(strcmp($dlVal, '')) {
$item.= '<div class="typo3-TCEforms-originalLanguageValue">'.$this->getLanguageIcon($table, $row, 'v'.$prL['ISOcode']).$this->previewFieldValue($dlVal, $fCfg).'&nbsp;</div>';
}
}
}
}
return $item;
t3lib/jsfunc.inline.js (Revision 3042)
*
* Copyright notice
*
* (c) 2006-2007 Oliver Hader <oh@inpublica.de>
* (c) 2006-2008 Oliver Hader <oh@inpublica.de>
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
......
if (ucFormObj.length) ucFormObj[0].value = value;
},
createNewRecord: function(objectId,prevRecordUid) {
createNewRecord: function(objectId, recordUid) {
if (this.isBelowMax(objectId)) {
if (prevRecordUid) {
objectId += '['+prevRecordUid+']';
if (recordUid) {
objectId += '['+recordUid+']';
}
this.makeAjaxCall('createNewRecord', [this.getNumberOfRTE(), objectId], true);
} else {
......
return false;
},
synchronizeLocalizeRecords: function(objectId, type) {
var parameters = [this.getNumberOfRTE(), objectId, type];
this.makeAjaxCall('synchronizeLocalizeRecords', parameters, true);
},
setExpandedCollapsedState: function(objectId, expand, collapse) {
this.makeAjaxCall('setExpandedCollapsedState', [objectId, expand, collapse]);
},
......
if (this.data.unique && this.data.unique[objectPrefix]) {
var unique = this.data.unique[objectPrefix];
var fieldObj = elName ? document.getElementsByName(elName+'['+unique.field+']') : null;
if (unique.type == 'select') {
if (fieldObj && fieldObj.length) {
delete(this.data.unique[objectPrefix].used[recordUid])
if (unique.selector == 'select') {
if (!isNaN(fieldObj[0].value)) {
var selector = $(objectPrefix+'_selector');
this.readdSelectOption(selector, fieldObj[0].value, unique);
}
}
if (!(unique.selector && unique.max == -1)) {
var formName = this.prependFormFieldNames+this.parseFormElementName('parts', objectPrefix, 3, 1);
var formObj = document.getElementsByName(formName);
......
return false;
},
deleteRecord: function(objectId) {
deleteRecord: function(objectId, options) {
var i, j, inlineRecords, records, childObjectId, childTable;
var objectPrefix = this.parseFormElementName('full', objectId, 0 , 1);
var elName = this.parseFormElementName('full', objectId, 2);
......
}
// If the record is new and was never saved before, just remove it from DOM:
if (this.isNewRecord(objectId)) {
new Effect.Fade(objectId+'_div', { afterFinish: function() { Element.remove(objectId+'_div'); } });
if (this.isNewRecord(objectId) || options && options.forceDirectRemoval) {
this.fadeAndRemove(objectId+'_div');
// If the record already exists in storage, mark it to be deleted on clicking the save button:
} else {
document.getElementsByName('cmd'+shortName+'[delete]')[0].disabled = false;
......
md5 = this.data.config[objectPrefix].md5;
}
return md5
},
fadeAndRemove: function(element) {
if ($(element)) {
new Effect.Fade(element, { afterFinish: function() { Element.remove(element); } });
}
}
}
t3lib/class.t3lib_befunc.php (Revision 3042)
return $outQ;
}
/**
* Fetches the localization for a given record.
*
* @param string $table: Table name present in $TCA
* @param integer $uid: The uid of the record
* @param ?nteger $language: The uid of the language record in sys_language
* @param string $andWhereClause: Optional additional WHERE clause (default: '')
* @return mixed Multidimensional array with selected records; if none exist, false is returned
*/
public function getRecordLocalization($table, $uid, $language, $andWhereClause='') {
$recordLocalization = false;
if (isset($GLOBALS['TCA'][$table]['ctrl'])) {
$tcaCtrl =& $GLOBALS['TCA'][$table]['ctrl'];
if (isset($tcaCtrl['transOrigPointerField']) && isset($tcaCtrl['languageField'])) {
$recordLocalization = t3lib_BEfunc::getRecordsByField(
$table,
$tcaCtrl['transOrigPointerField'],
$uid,
'AND '.$tcaCtrl['languageField'].'='.intval($language).($andWhereClause ? ' '.$andWhereClause : ''),
'',
'',
'1'
);
}
}
return $recordLocalization;
}
......
/*******************************************
*
* SQL-related, DEPRECATED functions
......
}
/**
* Determines whether a table is localizable and has the languageField and transOrigPointerField set in $TCA.
*
* @param string $table: The table to check
* @return boolean Whether a table is localizable
*/
public function isTableLocalizable($table) {
$isLocalizable = false;
if (isset($GLOBALS['TCA'][$table]['ctrl']) && is_array($GLOBALS['TCA'][$table]['ctrl'])) {
$tcaCtrl =& $GLOBALS['TCA'][$table]['ctrl'];
$isLocalizable = (isset($tcaCtrl['languageField']) && $tcaCtrl['languageField'] && isset($tcaCtrl['transOrigPointerField']) && $tcaCtrl['transOrigPointerField']);
}
return $isLocalizable;
}
/**
* Returns the value of the property localizationMode in the given $config array ($TCA[<table>]['columns'][<field>]['config']).
* If the table is prepared for localization and no localizationMode is set, 'select' is returned by default.
* If the table is not prepared for localization or not defined at all in $TCA, false is returned.
*
* @param string $table: The name of the table to lookup in TCA
* @param mixed $fieldOrConfig: The fieldname (string) or the configuration of the field to check (array)
* @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
*/
public function getInlineLocalizationMode($table, $fieldOrConfig) {
$localizationMode = false;
if (is_array($fieldOrConfig) && count($fieldOrConfig)) {
$config = $fieldOrConfig;
} elseif (is_string($fieldOrConfig) && isset($GLOBALS['TCA'][$table]['columns'][$field]['config'])) {
$config = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
}
if (is_array($config) && isset($config['type']) && $config['type']=='inline' && self::isTableLocalizable($table)) {
$localizationMode = (isset($config['behaviour']['localizationMode']) && $config['behaviour']['localizationMode'] ? $config['behaviour']['localizationMode'] : 'select');
// The mode 'select' is not possible when child table is not localizable at all:
if ($localizationMode=='select' && !self::isTableLocalizable($config['foreign_table'])) {
$localizationMode = false;
}
}
return $localizationMode;
}
/**
* 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.
* If $id is zero a pseudo root-page with "_thePath" set is returned IF the current BE_USER is admin.
* In any case ->isInWebMount must return true for the user (regardless of $perms_clause)
t3lib/class.t3lib_tceforms_inline.php (Revision 3042)
/***************************************************************
* Copyright notice
*
* (c) 2006-2007 Oliver Hader <oh@inpublica.de>
* (c) 2006-2008 Oliver Hader <oh@inpublica.de>
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
......
*/
function getSingleField_typeInline($table,$field,$row,&$PA) {
// check the TCA configuration - if false is returned, something was wrong
if ($this->checkConfiguration($PA['fieldConf']['config']) === false) return false;
if ($this->checkConfiguration($PA['fieldConf']['config']) === false) {
return false;
}
// count the number of processed inline elements
$this->inlineCount++;
......
$foreign_table = $config['foreign_table'];
t3lib_div::loadTCA($foreign_table);
if (t3lib_BEfunc::isTableLocalizable($table)) {
$language = intval($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]);
}
$minitems = t3lib_div::intInRange($config['minitems'],0);
$maxitems = t3lib_div::intInRange($config['maxitems'],0);
if (!$maxitems) $maxitems=100000;
......
// e.g. inline[<pid>][<table1>][<uid1>][<field1>][<table2>][<uid2>][<field2>]
$nameObject = $this->inlineNames['object'];
// get the records related to this inline record
$recordList = $this->getRelatedRecords($table,$field,$row,$PA,$config);
$relatedRecords = $this->getRelatedRecords($table,$field,$row,$PA,$config);
// set the first and last record to the config array
$config['inline']['first'] = $recordList[0]['uid'];
$config['inline']['last'] = $recordList[count($recordList)-1]['uid'];
$config['inline']['first'] = $relatedRecords['records'][0]['uid'];
$config['inline']['last'] = $relatedRecords['records'][$relatedRecords['count']-1]['uid'];
// Tell the browser what we have (using JSON later):
$top = $this->getStructureLevel(0);
......
// If uniqueness *and* selector are set, they should point to the same field - so, get the configuration of one:
$selConfig = $this->getPossibleRecordsSelectorConfig($config, $config['foreign_unique']);
// Get the used unique ids:
$uniqueIds = $this->getUniqueIds($recordList, $config, $selConfig['type']=='groupdb');
$uniqueIds = $this->getUniqueIds($relatedRecords['records'], $config, $selConfig['type']=='groupdb');
$possibleRecords = $this->getPossibleRecords($table,$field,$row,$config,'foreign_unique');
$uniqueMax = $config['appearance']['useCombination'] || $possibleRecords === false ? -1 : count($possibleRecords);
$this->inlineData['unique'][$nameObject.'['.$foreign_table.']'] = array(
......
$item .= '<div id="'.$nameObject.'">';
// define how to show the "Create new record" link - if there are more than maxitems, hide it
if (count($recordList) >= $maxitems || ($uniqueMax > 0 && count($recordList) >= $uniqueMax)) {
if ($relatedRecords['count'] >= $maxitems || ($uniqueMax > 0 && $relatedRecords['count'] >= $uniqueMax)) {
$config['inline']['inlineNewButtonStyle'] = 'display: none;';
}
// add the "Create new record" link before all child records
if (in_array($config['appearance']['newRecordLinkPosition'], array('both', 'top'))) {
$item .= $this->getNewRecordLink($nameObject.'['.$foreign_table.']', $config);
// Render the level links (create new record, localize all, synchronize):
if ($config['appearance']['levelLinksPosition']!='none') {
$levelLinks = $this->getLevelInteractionLink('newRecord', $nameObject.'['.$foreign_table.']', $config);
if ($language>0) {
// Add the "Localize all records" link before all child records:
if (isset($config['appearance']['showAllLocalizationLink']) && $config['appearance']['showAllLocalizationLink']) {
$levelLinks.= $this->getLevelInteractionLink('localize', $nameObject.'['.$foreign_table.']', $config);
}
// Add the "Synchronize with default language" link before all child records:
if (isset($config['appearance']['showSynchronizationLink']) && $config['appearance']['showSynchronizationLink']) {
$levelLinks.= $this->getLevelInteractionLink('synchronize', $nameObject.'['.$foreign_table.']', $config);
}
}
}
// Add the level links before all child records:
if (in_array($config['appearance']['levelLinksPosition'], array('both', 'top'))) {
$item.= $levelLinks;
}
$item .= '<div id="'.$nameObject.'_records">';
$relationList = array();
if (count($recordList)) {
foreach ($recordList as $rec) {
if (count($relatedRecords['records'])) {
foreach ($relatedRecords['records'] as $rec) {
$item .= $this->renderForeignRecord($row['uid'],$rec,$config);
$relationList[] = $rec['uid'];
if (!isset($rec['__virtual']) || !$rec['__virtual']) {
$relationList[] = $rec['uid'];
}
}
}
$item .= '</div>';
// add the "Create new record" link after all child records
if (in_array($config['appearance']['newRecordLinkPosition'], array('both', 'bottom'))) {
$item .= $this->getNewRecordLink($nameObject.'['.$foreign_table.']', $config);
// Add the level links after all child records:
if (in_array($config['appearance']['levelLinksPosition'], array('both', 'bottom'))) {
$item.= $levelLinks;
}
// add Drag&Drop functions for sorting to TCEforms::$additionalJS_post
......
$foreign_field = $config['foreign_field'];
$foreign_selector = $config['foreign_selector'];
// Register default localization content:
$parent = $this->getStructureLevel(-1);
if (isset($parent['localizationMode']) && $parent['localizationMode']!=false) {
$this->fObj->registerDefaultLanguageData($foreign_table, $rec);
}
// Send a mapping information to the browser via JSON:
// e.g. data[<curTable>][<curId>][<curField>] => data[<pid>][<parentTable>][<parentId>][<parentField>][<curTable>][<curId>][<curField>]
$this->inlineData['map'][$this->inlineNames['form']] = $this->inlineNames['object'];
// Set this variable if we handle a brand new unsaved record:
$isNewRecord = t3lib_div::testInt($rec['uid']) ? false : true;
// Set this variable if the record is virtual and only show with header and not editable fields:
$isVirtualRecord = (isset($rec['__virtual']) && $rec['__virtual']);
// If there is a selector field, normalize it:
if ($foreign_selector) {
$rec[$foreign_selector] = $this->normalizeUid($rec[$foreign_selector]);
}
$hasAccess = $this->checkAccess($isNewRecord?'new':'edit', $foreign_table, $rec['uid']);
if (!$this->checkAccess(($isNewRecord ? 'new' : 'edit'), $foreign_table, $rec['uid'])) {
return false;
}
if(!$hasAccess) return false;
// Get the current naming scheme for DOM name/id attributes:
$nameObject = $this->inlineNames['object'];
$appendFormFieldNames = '['.$foreign_table.']['.$rec['uid'].']';
......
// Put the current level also to the dynNestedStack of TCEforms:
$this->fObj->pushToDynNestedStack('inline', $this->inlineNames['object'].$appendFormFieldNames);
$header = $this->renderForeignRecordHeader($parentUid, $foreign_table, $rec, $config);
$combination = $this->renderCombinationTable($rec, $appendFormFieldNames, $config);
$fields = $this->renderMainFields($foreign_table, $rec);
$fields = $this->wrapFormsSection($fields);
$header = $this->renderForeignRecordHeader($parentUid, $foreign_table, $rec, $config, $isVirtualRecord);
if (!$isVirtualRecord) {
$combination = $this->renderCombinationTable($rec, $appendFormFieldNames, $config);
$fields = $this->renderMainFields($foreign_table, $rec);
$fields = $this->wrapFormsSection($fields);
if ($isNewRecord) {
// show this record expanded or collapsed
$isExpanded = is_array($config['appearance']) && $config['appearance']['collapseAll'] ? 1 : 0;
// get the top parent table
$top = $this->getStructureLevel(0);
$ucFieldName = 'uc['.$top['table'].']['.$top['uid'].']'.$appendFormFieldNames;
// set additional fields for processing for saving
$fields .= '<input type="hidden" name="'.$this->prependFormFieldNames.$appendFormFieldNames.'[pid]" value="'.$rec['pid'].'"/>';
$fields .= '<input type="hidden" name="'.$ucFieldName.'" value="'.$isExpanded.'" />';
if ($isNewRecord) {
// show this record expanded or collapsed
$isExpanded = is_array($config['appearance']) && $config['appearance']['collapseAll'] ? 1 : 0;
// get the top parent table
$top = $this->getStructureLevel(0);
$ucFieldName = 'uc['.$top['table'].']['.$top['uid'].']'.$appendFormFieldNames;
// set additional fields for processing for saving
$fields .= '<input type="hidden" name="'.$this->prependFormFieldNames.$appendFormFieldNames.'[pid]" value="'.$rec['pid'].'"/>';
$fields .= '<input type="hidden" name="'.$ucFieldName.'" value="'.$isExpanded.'" />';
} else {
// show this record expanded or collapsed
$isExpanded = $this->getExpandedCollapsedState($foreign_table, $rec['uid']);
// set additional field for processing for saving
$fields .= '<input type="hidden" name="'.$this->prependCmdFieldNames.$appendFormFieldNames.'[delete]" value="1" disabled="disabled" />';
} else {
// show this record expanded or collapsed
$isExpanded = $this->getExpandedCollapsedState($foreign_table, $rec['uid']);
// set additional field for processing for saving
$fields .= '<input type="hidden" name="'.$this->prependCmdFieldNames.$appendFormFieldNames.'[delete]" value="1" disabled="disabled" />';
}
// if this record should be shown collapsed
if (!$isExpanded) $appearanceStyleFields = ' style="display: none;"';
}
// if this record should be shown collapsed
if (!$isExpanded) $appearanceStyleFields = ' style="display: none;"';
// set the record container with data for output
$out = '<div id="'.$formFieldNames.'_header">'.$header.'</div>';
$out .= '<div id="'.$formFieldNames.'_fields"'.$appearanceStyleFields.'>'.$fields.$combination.'</div>';
......
* @param string $foreign_table: The foreign_table we create a header for
* @param array $rec: The current record of that foreign_table
* @param array $config: content of $PA['fieldConf']['config']
* @param boolean $isVirtualRecord:
* @return string The HTML code of the header
*/
function renderForeignRecordHeader($parentUid, $foreign_table, $rec, $config = array()) {
function renderForeignRecordHeader($parentUid, $foreign_table, $rec, $config, $isVirtualRecord=false) {
// Init:
$formFieldNames = $this->inlineNames['object'].'['.$foreign_table.']['.$rec['uid'].']';
$expandSingle = $config['appearance']['expandSingle'] ? 1 : 0;
......
}
$altText = t3lib_BEfunc::getRecordIconAltText($rec, $foreign_table);
$iconImg =
'<a href="#" onclick="'.htmlspecialchars($onClick).'">'.t3lib_iconWorks::getIconImage(
$foreign_table, $rec, $this->backPath,
'title="'.htmlspecialchars($altText).'" class="absmiddle"'
).'</a>';
$iconImg = t3lib_iconWorks::getIconImage($foreign_table, $rec, $this->backPath, 'title="'.htmlspecialchars($altText).'" class="absmiddle"');
$label = '<span id="'.$formFieldNames.'_label">'.$recTitle.'</span>';
if (!$isVirtualRecord) {
$iconImg = $this->wrapWithAnchor($iconImg, '#', array('onclick' => $onClick));
$label = $this->wrapWithAnchor($label, '#', array('onclick' => $onClick, 'style' => 'display: block;'));
}
$label =
'<a href="#" onclick="'.htmlspecialchars($onClick).'" style="display: block;">'.
'<span id="'.$formFieldNames.'_label">'.$recTitle.'</span>'.
'</a>';
$ctrl = $this->renderForeignRecordHeaderControl($parentUid, $foreign_table, $rec, $config, $isVirtualRecord);
$ctrl = $this->renderForeignRecordHeaderControl($parentUid, $foreign_table, $rec, $config);
// @TODO: Check the table wrapping and the CSS definitions
$header =
'<table cellspacing="0" cellpadding="0" border="0" width="100%" style="margin-right: '.$this->inlineStyles['margin-right'].'px;"'.
......
* @param array $config: (modified) TCA configuration of the field
* @return string The HTML code with the control-icons
*/
function renderForeignRecordHeaderControl($parentUid, $foreign_table, $rec, $config = array()) {
function renderForeignRecordHeaderControl($parentUid, $foreign_table, $rec, $config=array(), $isVirtualRecord=false) {
// Initialize:
$cells = array();
$isNewItem = substr($rec['uid'], 0, 3) == 'NEW';
......
// Icon to visualize that a required field is nested in this inline level:
$cells[] = '<img name="'.$nameObjectFtId.'_req" src="clear.gif" width="10" height="10" hspace="4" vspace="3" alt="" />';
if (isset($rec['__create'])) {
$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="" />';
} elseif (isset($rec['__remove'])) {
$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="" />';
}
// "Info": (All records)
if (!$isNewItem)
if (!$isNewItem) {
$cells[]='<a href="#" onclick="'.htmlspecialchars('top.launchView(\''.$foreign_table.'\', \''.$rec['uid'].'\'); return false;').'">'.
'<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="" />'.
'</a>';
}
// If the table is NOT a read-only table, then show these links:
if (!$tcaTableCtrl['readOnly']) {
if (!$tcaTableCtrl['readOnly'] && !$isVirtualRecord) {
// "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):
if ($enableManualSorting || $tcaTableCtrl['useColumnsForDefaultValues']) {
......
}
// "Delete" link:
if (
($isPagesTable && ($localCalcPerms&4)) || (!$isPagesTable && ($calcPerms&16))
) {
if ($isPagesTable && $localCalcPerms&4 || !$isPagesTable && $calcPerms&16) {
$onClick = "inline.deleteRecord('".$nameObjectFtId."');";
$cells[]='<a href="#" onclick="'.htmlspecialchars('if (confirm('.$GLOBALS['LANG']->JScharCode($GLOBALS['LANG']->getLL('deleteWarning')).')) { '.$onClick.' } return false;').'">'.
'<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="" />'.
'</a>';
}
// If this is a virtual record offer a minimized set of icons for user interaction:
} elseif ($isVirtualRecord) {
if (isset($rec['__create'])) {
$onClick = "inline.synchronizeLocalizeRecords('".$nameObjectFt."', ".$rec['uid'].");";
$cells[] = '<a href="#" onclick="'.htmlspecialchars($onClick).'">' .
'<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="" />' .
'</a>';
}
}
// If the record is edit-locked by another user, we will show a little warning sign:
......
/**
* Creates the HTML code of a general link to be used on a level of inline children.
* The possible keys for the parameter $type are 'newRecord', 'localize' and 'synchronize'.
*
* @param string $type: The link type, values are 'newRecord', 'localize' and 'synchronize'.
* @param string $objectPrefix: The "path" to the child record to create (e.g. 'data[parten_table][parent_uid][parent_field][child_table]')
* @param array $conf: TCA configuration of the parent(!) field
* @return string The HTML code of the new link, wrapped in a div
*/
protected function getLevelInteractionLink($type, $objectPrefix, $conf=array()) {
$nameObject = $this->inlineNames['object'];
$attributes = array();
switch($type) {
case 'newRecord':
$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:cm.createnew', 1);
$iconFile = 'gfx/new_el.gif';
// $iconAddon = 'width="11" height="12"';
$className = 'typo3-newRecordLink';
$attributes['class'] = 'inlineNewButton '.$this->inlineData['config'][$nameObject]['md5'];
$attributes['onclick'] = "return inline.createNewRecord('$objectPrefix')";
if (isset($conf['inline']['inlineNewButtonStyle']) && $conf['inline']['inlineNewButtonStyle']) {
$attributes['style'] = $conf['inline']['inlineNewButtonStyle'];
}
if (isset($conf['appearance']['newRecordLinkAddTitle']) && $conf['appearance']['newRecordLinkAddTitle']) {
$titleAddon = ' '.$GLOBALS['LANG']->sL($GLOBALS['TCA'][$conf['foreign_table']]['ctrl']['title'], 1);
}
break;
case 'localize':
$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:localizeAllRecords', 1);
$iconFile = 'gfx/localize_el.gif';
$className = 'typo3-localizationLink';
$attributes['onclick'] = "return inline.synchronizeLocalizeRecords('$objectPrefix', 'localize')";
break;
case 'synchronize':
$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:synchronizeWithOriginalLanguage', 1);
$iconFile = 'gfx/synchronize_el.gif';
$className = 'typo3-synchronizationLink';
$attributes['class'] = 'inlineNewButton '.$this->inlineData['config'][$nameObject]['md5'];
$attributes['onclick'] = "return inline.synchronizeLocalizeRecords('$objectPrefix', 'synchronize')";
break;
}
// Create the link:
$icon = ($iconFile ? '<img'.t3lib_iconWorks::skinImg($this->backPath, $iconFile, $iconAddon).' alt="'.htmlspecialchars($title.$titleAddon).'" />' : '');
$link = $this->wrapWithAnchor($icon.$title.$titleAddon, '#', $attributes);
return '<div'.($className ? ' class="'.$className.'"' : '').$link.'</div>';
}
/**
* Creates a link/button to create new records
*
* @param string $objectPrefix: The "path" to the child record to create (e.g. '[parten_table][parent_uid][parent_field][child_table]')
* @param array $conf: TCA configuration of the parent(!) field
* @return string The HTML code for the new record link
* @deprecated since TYPO3 4.2.0-beta1
*/
function getNewRecordLink($objectPrefix, $conf = array()) {
$nameObject = $this->inlineNames['object'];
$class = ' class="inlineNewButton '.$this->inlineData['config'][$nameObject]['md5'].'"';
if ($conf['inline']['inlineNewButtonStyle']) {
$style = ' style="'.$conf['inline']['inlineNewButtonStyle'].'"';
}
$onClick = "return inline.createNewRecord('$objectPrefix')";
$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:cm.createnew',1);
if ($conf['appearance']['newRecordLinkAddTitle']) {
$tableTitle .= ' '.$GLOBALS['LANG']->sL($GLOBALS['TCA'][$conf['foreign_table']]['ctrl']['title'],1);
}
$out = '
<div class="typo3-newRecordLink">
<a href="#" onClick="'.$onClick.'"'.$class.$style.' title="'.$title.$tableTitle.'">'.
'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/new_el.gif','width="11" height="12"').' alt="'.$title.$tableTitle.'" />'.
$title.t3lib_div::fixed_lgd_cs($tableTitle, $this->fObj->titleLen).
'</a>
</div>';
return $out;
return $this->getLevelInteractionLink('newRecord', $objectPrefix, $conf);
}
......
$ajaxMethod = $ajaxIdParts[1];
switch ($ajaxMethod) {
case 'createNewRecord':
case 'synchronizeLocalizeRecords':
$this->isAjaxCall = true;
// Construct runtime environment for Inline Relational Record Editing:
$this->processAjaxRequestConstruct($ajaxArguments);
// Parse the DOM identifier (string), add the levels to the structure stack (array) and load the TCA config:
$this->parseStructureString($ajaxArguments[0], true);
// Render content:
$ajaxObj->setContentFormat('jsonbody');
$ajaxObj->setContent(
call_user_func_array(array(&$this, $ajaxMethod), $ajaxArguments)
......
/**
* Determines and sets several script calls to a JSON array, that would have been executed if processed in non-AJAX mode.
*
* @param array &$jsonArray: Reference of the array to be used for JSON
* @param array $config: The configuration of the IRRE field of the parent record
* @return void
*/
protected function getCommonScriptCalls(&$jsonArray, $config) {
// Add data that would have been added at the top of a regular TCEforms call:
if ($headTags = $this->getHeadTags()) {
$jsonArray['headData'] = $headTags;
}
// Add the JavaScript data that would have been added at the bottom of a regular TCEforms call:
$jsonArray['scriptCall'][] = $this->fObj->JSbottom($this->fObj->formName, true);
// If script.aculo.us Sortable is used, update the Observer to know the record:
if ($config['appearance']['useSortable']) {
$jsonArray['scriptCall'][] = "inline.createDragAndDropSorting('".$this->inlineNames['object']."_records');";
}
// if TCEforms has some JavaScript code to be executed, just do it
if ($this->fObj->extJSCODE) {
$jsonArray['scriptCall'][] = $this->fObj->extJSCODE;
}
}
/**
* Initialize environment for AJAX calls
*
* @param string $method: Name of the method to be called
......
* @return array An array to be used for JSON
*/
function createNewRecord($domObjectId, $foreignUid = 0) {
$this->isAjaxCall = true;
// parse the DOM identifier (string), add the levels to the structure stack (array) and load the TCA config
$this->parseStructureString($domObjectId, true);
// the current table - for this table we should add/import records
$current = $this->inlineStructure['unstable'];
// the parent table - this table embeds the current table
......
// dynamically create a new record using t3lib_transferData
if (!$foreignUid || !t3lib_div::testInt($foreignUid) || $config['foreign_selector']) {
$record = $this->getNewRecord($this->inlineFirstPid, $current['table']);
// Set language of new child record to the language of the parent record:
if ($config['localizationMode']=='select') {
$parentRecord = $this->getRecord(0, $parent['table'], $parent['uid']);
$parentLanguageField = $GLOBALS['TCA'][$parent['table']]['ctrl']['languageField'];
$childLanguageField = $GLOBALS['TCA'][$current['table']]['ctrl']['languageField'];
if ($parentRecord[$languageField]>0) {
$record[$childLanguageField] = $parentRecord[$languageField];
}
}
// dynamically import an existing record (this could be a call from a select box)
} else {
......
)
);
}
// Add data that would have been added at the top of a regular TCEforms call:
if ($headTags = $this->getHeadTags()) {
$jsonArray['headData'] = $headTags;
}
// Add the JavaScript data that would have been added at the bottom of a regular TCEforms call:
$jsonArray['scriptCall'][] = $this->fObj->JSbottom($this->fObj->formName, true);
// if script.aculo.us Sortable is used, update the Observer to know the the record
if ($config['appearance']['useSortable'])
$jsonArray['scriptCall'][] = "inline.createDragAndDropSorting('".$this->inlineNames['object']."_records');";
// if TCEforms has some JavaScript code to be executed, just do it
if ($this->fObj->extJSCODE)
$jsonArray['scriptCall'][] = $this->fObj->extJSCODE;
$this->getCommonScriptCalls($jsonArray, $config);
// tell the browser to scroll to the newly created record
$jsonArray['scriptCall'][] = "Element.scrollTo('".$objectId."_div');";
// fade out and fade in the new record in the browser view to catch the user's eye
......
/**
* Handle AJAX calls to localize all records of a parent, localize a single record or to synchronize with the original language parent.
*
* @param string $domObjectId: The calling object in hierarchy, that requested a new record.
* @param mixed $type: Defines the type 'localize' or 'synchronize' (string) or a single uid to be localized (integer)
* @return array An array to be used for JSON
*/
protected function synchronizeLocalizeRecords($domObjectId, $type) {
$jsonArray = false;
if (t3lib_div::inList('localize,synchronize', $type) || t3lib_div::testInt($type)) {
// The current level:
$current = $this->inlineStructure['unstable'];
// The parent level:
$parent = $this->getStructureLevel(-1);
$parentRecord = $this->getRecord(0, $parent['table'], $parent['uid']);
$cmd = array();
$cmd[$parent['table']][$parent['uid']]['inlineLocalizeSynchronize'] = $parent['field'].','.$type;
/* @var t3lib_TCEmain */
$tce = t3lib_div::makeInstance('t3lib_TCEmain');
$tce->stripslashes_values = false;
$tce->start(array(), $cmd);
$tce->process_cmdmap();
$newItemList = $tce->registerDBList[$parent['table']][$parent['uid']][$parent['field']];
unset($tce);
$jsonArray = $this->getExecuteChangesJsonArray($parentRecord[$parent['field']], $newItemList);
$this->getCommonScriptCalls($jsonArray, $parent['config']);
}
return $jsonArray;
}
/**
* Generates a JSON array which executes the changes and thus updates the forms view.
*
* @param string $oldItemList: List of related child reocrds before changes were made (old)
* @param string $newItemList: List of related child records after changes where made (new)
* @return array An array to be used for JSON
*/
protected function getExecuteChangesJsonArray($oldItemList, $newItemList) {
$parent = $this->getStructureLevel(-1);
$current = $this->inlineStructure['unstable'];
$jsonArray = array('scriptCall' => array());
$jsonArrayScriptCall =& $jsonArray['scriptCall'];
$nameObject = $this->inlineNames['object'];
$nameObjectForeignTable = $nameObject.'['.$current['table'].']';
// Get the name of the field pointing to the original record:
$transOrigPointerField = $GLOBALS['TCA'][$current['table']]['ctrl']['transOrigPointerField'];
// Get the name of the field used as foreign selector (if any):
$foreignSelector = (isset($parent['config']['foreign_selector']) && $parent['config']['foreign_selector'] ? $parent['config']['foreign_selector'] : false);
// Convert lists to array with uids of child records:
$oldItems = $this->getRelatedRecordsUidArray($oldItemList);
$newItems = $this->getRelatedRecordsUidArray($newItemList);
// Determine the items that were localized or localized:
$removedItems = array_diff($oldItems, $newItems);
$localizedItems = array_diff($newItems, $oldItems);
// Set the items that should be removed in the forms view:
foreach ($removedItems as $item) {
$jsonArrayScriptCall[] = "inline.deleteRecord('".$nameObjectForeignTable.'['.$item.']'."', {forceDirectRemoval: true});";
}
// Set the items that should be added in the forms view:
foreach ($localizedItems as $item) {
$row = $this->getRecord($this->inlineFirstPid, $current['table'], $item);
$selectedValue = ($foreignSelector ? "'".$row[$foreignSelector]."'" : 'null');
$data.= $this->renderForeignRecord($parent['uid'], $row, $parent['config']);
$jsonArrayScriptCall[] = "inline.memorizeAddRecord('$nameObjectForeignTable', '".$item."', null, $selectedValue);";
// Remove possible virtual records in the form which showed that a child records could be localized:
if (isset($row[$transOrigPointerField]) && $row[$transOrigPointerField]) {
$jsonArrayScriptCall[] = "inline.fadeAndRemove('".$nameObjectForeignTable.'['.$row[$transOrigPointerField].']_div'."');";
}
}
if ($data) {
$data = $GLOBALS['LANG']->csConvObj->utf8_encode($data, $GLOBALS['LANG']->charSet);
$jsonArray['data'] = $data;
array_unshift(
$jsonArrayScriptCall,
"inline.domAddNewRecord('bottom', '".$nameObject."_records', '$nameObjectForeignTable', json.data);"
);
}
return $jsonArray;
}
/**
* Save the expanded/collapsed state of a child record in the BE_USER->uc.
*
* @param string $domObjectId: The calling object in hierarchy, that requested a new record.
......
/**
* Get the related records of the embedding item, this could be 1:n, m:n.
* Returns an associative array with the keys records and count. 'count' contains only real existing records on the current parent record.
*
* @param string $table: The table name of the record
* @param string $field: The field name which this element is supposed to edit
* @param array $row: The record data array where the value(s) for the field can be found
* @param array $PA: An array with additional configuration options.
* @param array $config: (Redundant) content of $PA['fieldConf']['config'] (for convenience)
* @return array The records related to the parent item
* @return array The records related to the parent item as associative array.
*/
function getRelatedRecords($table,$field,$row,&$PA,$config) {
function getRelatedRecords($table, $field, $row, &$PA, $config) {
$records = array();
$pid = $row['pid'];
$elements = $PA['itemFormElValue'];
$foreignTable = $config['foreign_table'];
// Creating the label for the "No Matching Value" entry.
$nMV_label = isset($PA['fieldTSConfig']['noMatchingValue_label']) ? $this->fObj->sL($PA['fieldTSConfig']['noMatchingValue_label']) : '[ '.$this->fObj->getLL('l_noMatchingValue').' ]';
$localizationMode = t3lib_BEfunc::getInlineLocalizationMode($table, $config);
// Register the required number of elements:
# $this->fObj->requiredElements[$PA['itemFormElName']] = array($minitems,$maxitems,'imgName'=>$table.'_'.$row['uid'].'_'.$field);
if ($localizationMode!=false) {
$language = intval($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]);
$transOrigPointer = intval($row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]);
if ($language>0 && $transOrigPointer) {
// Localization in mode 'keep', isn't a real localization, but keeps the children of the original parent record:
if ($localizationMode=='keep') {
$transOrigRec = $this->getRecord(0, $table, $transOrigPointer);
$elements = $transOrigRec[$field];
$pid = $transOrigRec['pid'];
// Localization in modes 'select', 'all' or 'sync' offer a dynamic localization and synchronization with the original language record:
} elseif ($localizationMode=='select') {
$transOrigRec = $this->getRecord(0, $table, $transOrigPointer);
$pid = $transOrigRec['pid'];
$recordsOriginal = $this->getRelatedRecordsArray($pid, $foreignTable, $transOrigRec[$field]);
}
}
}
$records = $this->getRelatedRecordsArray($pid, $foreignTable, $elements);
$relatedRecords = array('records' => $records, 'count' => count($records));
// Merge original language with current localization and show differences:
if (is_array($recordsOriginal)) {
$options = array(
'showPossible' => (isset($config['appearance']['showPossibleLocalizationRecords']) && $config['appearance']['showPossibleLocalizationRecords']),
'showRemoved' => (isset($config['appearance']['showRemovedLocalizationRecords']) && $config['appearance']['showRemovedLocalizationRecords']),
);
if ($options['showPossible'] || $options['showRemoved']) {
$relatedRecords['records'] = $this->getLocalizationDifferences($foreignTable, $options, $recordsOriginal, $records);
}
}
return $relatedRecords;
}
/**
* Gets the related records of the embedding item, this could be 1:n, m:n.
*
* @param integer $pid: The pid of the parent record
* @param string $table: The table name of the record
* @param string $itemList: The list of related child records
* @return array The records related to the parent item
*/
protected function getRelatedRecordsArray($pid, $table, $itemList) {
$records = array();
$itemArray = $this->getRelatedRecordsUidArray($itemList);
// Perform modification of the selected items array:
$itemArray = t3lib_div::trimExplode(',',$PA['itemFormElValue'],1);
foreach($itemArray as $tk => $tv) {
$tvP = explode('|',$tv,2);
// get the records for this uid using t3lib_transferdata
$records[] = $this->getRecord($row['pid'], $config['foreign_table'], $tvP[0]);
foreach($itemArray as $uid) {
// Get the records for this uid using t3lib_transferdata:
$records[$uid] = $this->getRecord($pid, $table, $uid);
}
return $records;
}
/**
* Gets an array with the uids of related records out of a list of items.
* This list could contain more information than required. This methods just
* extracts the uids.
*
* @param string $itemList: The list of related child records
* @return array An array with uids
*/
protected function getRelatedRecordsUidArray($itemList) {
$itemArray = t3lib_div::trimExplode(',', $itemList, 1);
// Perform modification of the selected items array:
foreach($itemArray as $key => &$value) {
$parts = explode('|', $value, 2);
$value = $parts[0];
}
return $itemArray;
}
/**
* Gets the difference between current localized structure and the original language structure.
* If there are records which once were localized but don't exist in the original version anymore, the record row is marked with '__remove'.
* If there are records which can be localized and exist only in the original version, the record row is marked with '__create' and '__virtual'.
*
* @param string $table: The table name of the parent records
* @param array $options: Options defining what kind of records to display
* @param array $recordsOriginal: The uids of the child records of the original language
* @param array $recordsLocalization: The uids of the child records of the current localization
* @return array Merged array of uids of the child records of both versions
*/
protected function getLocalizationDifferences($table, array $options, array $recordsOriginal, array $recordsLocalization) {
$records = array();
$transOrigPointerField = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'];
// Compare original to localized version of the records:
foreach ($recordsLocalization as $uid => $row) {
// If the record points to a original translation which doesn't exist anymore, it could be removed:
if (isset($row[$transOrigPointerField]) && $row[$transOrigPointerField]>0) {
$transOrigPointer = $row[$transOrigPointerField];
if (isset($recordsOriginal[$transOrigPointer])) {
unset($recordsOriginal[$transOrigPointer]);
} elseif ($options['showRemoved']) {
$row['__remove'] = true;
}
}
$records[$uid] = $row;
}
// Process the remaining records in the original unlocalized parent:
if ($options['showPossible']) {
foreach ($recordsOriginal as $uid => $row) {
$row['__create'] = true;
$row['__virtual'] = true;
$records[$uid] = $row;
}
}
return $records;
}
......
$foreignConfig = $this->getPossibleRecordsSelectorConfig($conf, $foreign_check);
$PA = $foreignConfig['PA'];
$config = $PA['fieldConf']['config'];
if ($foreignConfig['type'] == 'select') {
// Getting the selector box items from the system
$selItems = $this->fObj->addSelectOptionsToItemArray($this->fObj->initItemArray($PA['fieldConf']),$PA['fieldConf'],$this->fObj->setTSconfig($table,$row),$field);
if ($config['itemsProcFunc']) $selItems = $this->fObj->procItems($selItems,$PA['fieldTSConfig']['itemsProcFunc.'],$config,$table,$row,$field);
// Possibly remove some items:
$removeItems = t3lib_div::trimExplode(',',$PA['fieldTSConfig']['removeItems'],1);
foreach($selItems as $tk => $p) {
// Checking languages and authMode:
$languageDeny = $tcaTableCtrl['languageField'] && !strcmp($tcaTableCtrl['languageField'], $field) && !$GLOBALS['BE_USER']->checkLanguageAccess($p[1]);
$authModeDeny = $config['form_type']=='select' && $config['authMode'] && !$GLOBALS['BE_USER']->checkAuthMode($table,$field,$p[1],$config['authMode']);
......
} elseif (isset($PA['fieldTSConfig']['altLabels.'][$p[1]])) {
$selItems[$tk][0]=$this->fObj->sL($PA['fieldTSConfig']['altLabels.'][$p[1]]);
}
// Removing doktypes with no access:
if ($table.'.'.$field == 'pages.doktype') {
if (!($GLOBALS['BE_USER']->isAdmin() || t3lib_div::inList($GLOBALS['BE_USER']->groupData['pagetypes_select'],$p[1]))) {
......
function getUniqueIds($records, $conf=array(), $splitValue=false) {
$uniqueIds = array();
if ($conf['foreign_unique'] && count($records)) {
if (isset($conf['foreign_unique']) && $conf['foreign_unique'] && count($records)) {
foreach ($records as $rec) {
$value = $rec[$conf['foreign_unique']];
// Split the value and extract the table and uid:
if ($splitValue) {
$valueParts = t3lib_div::trimExplode('|', $value);
$itemParts = explode('_', $valueParts[0]);
$value = array(
'uid' => array_pop($itemParts),
'table' => implode('_', $itemParts)
);
// Skip virtual records (e.g. shown in localization mode):
if (!isset($rec['__virtual']) || !$rec['__virtual']) {
$value = $rec[$conf['foreign_unique']];
// Split the value and extract the table and uid:
if ($splitValue) {
$valueParts = t3lib_div::trimExplode('|', $value);
$itemParts = explode('_', $valueParts[0]);
$value = array(
'uid' => array_pop($itemParts),
'table' => implode('_', $itemParts)
);
}
$uniqueIds[$rec['uid']] = $value;
}
$uniqueIds[$rec['uid']] = $value;
}
}
......
'uid' => $uid,
'field' => $field,
'config' => $config,
'localizationMode' => t3lib_BEfunc::getInlineLocalizationMode($table, $config),
);
$this->updateStructureNames();
}
......
* - 'unstable': Containting partly filled data (e.g. only table and possibly field)
*
* @param string $domObjectId: The DOM object-id
* @param boolean $loadConfig: Load the TCA configuration for that level
* @param boolean $loadConfig: Load the TCA configuration for that level (default: true)
* @return void
*/
function parseStructureString($string, $loadConfig = false) {
function parseStructureString($string, $loadConfig=true) {
$unstable = array();
$vector = array('table', 'uid', 'field');
$pattern = '/^'.$this->prependNaming.'\[(.+?)\]\[(.+)\]$/';
......
if (!$TSconfig['disabled']) {
$unstable['config'] = $this->fObj->overrideFieldConf($unstable['config'], $TSconfig);
}
$unstable['localizationMode'] = t3lib_BEfunc::getInlineLocalizationMode($unstable['table'], $unstable['config']);
}
$this->inlineStructure['stable'][] = $unstable;
$unstable = array();
......
* Does some checks on the TCA configuration of the inline field to render.
*
* @param array $config: Reference to the TCA field configuration
* @param string $table: The table name of the record
* @param string $field: The field name which this element is supposed to edit
* @param array $row: The record data array of the parent
* @return boolean If critical configuration errors were found, false is returned
*/
function checkConfiguration(&$config) {
......
return false;
}
// Init appearance if not set:
if (!is_array($config['appearance'])) {
if (!isset($config['appearance']) || !is_array($config['appearance'])) {
$config['appearance'] = array();
}
// 'newRecordLinkPosition' is deprecated since TYPO3 4.2.0-beta1, this is for backward compatibility:
if (!isset($config['appearance']['levelLinksPosition']) && isset($config['appearance']['newRecordLinkPosition']) && $config['appearance']['newRecordLinkPosition']) {
$config['appearance']['levelLinksPosition'] = $config['appearance']['newRecordLinkPosition'];
}
// Set the position/appearance of the "Create new record" link:
if ($config['foreign_selector'] && !$config['appearance']['useCombination']) {
$config['appearance']['newRecordLinkPosition'] = 'none';
} elseif (!in_array($config['appearance']['newRecordLinkPosition'], array('top', 'bottom', 'both', 'none'))) {
$config['appearance']['newRecordLinkPosition'] = 'top';
if (isset($config['foreign_selector']) && $config['foreign_selector'] && (!isset($config['appearance']['useCombination']) || !$config['appearance']['useCombination'])) {
$config['appearance']['levelLinksPosition'] = 'none';
} elseif (!isset($config['appearance']['levelLinksPosition']) || !in_array($config['appearance']['levelLinksPosition'], array('top', 'bottom', 'both', 'none'))) {
$config['appearance']['levelLinksPosition'] = 'top';
}
return true;
......
$type = false;
$table = false;
$selector = false;
if ($field) {
$PA = array();
$PA['fieldConf'] = $GLOBALS['TCA'][$foreign_table]['columns'][$field];
......
$selector = $type;
}
}
return array(
'PA' => $PA,
'type' => $type,
......
'selector' => $selector,
);
}
/**
* Determine the type of a record selector, e.g. select or group/db.
*
......
}
return $type;
}
/**
* Check, if a field should be skipped, that was defined to be handled as foreign_field or foreign_sortby of
* the parent record of the "inline"-type - if so, we have to skip this field - the rendering is done via "inline" as hidden field
......
return $headTags;
}
/**
* Wraps a text with an anchor and returns the HTML representation.
*
* @param string $text: The text to be wrapped by an anchor
* @param string $link: The link to be used in the anchor
* @param array $attributes: Array of attributes to be used in the anchor
* @return string The wrapped texted as HTML representation
*/
protected function wrapWithAnchor($text, $link, $attributes=array()) {
$link = trim($link);
$result = '<a href="'.($link ? $link : '#').'"';
foreach ($attributes as $key => $value) {
$result.= ' '.$key.'="'.htmlspecialchars(trim($value)).'"';
}
$result.= '>'.$text.'</a>';
return $result;
}
}
t3lib/class.t3lib_tcemain.php (Revision 3042)
/***************************************************************
* Copyright notice
*
* (c) 1999-2007 Kasper Skaarhoj (kasperYYYY@typo3.com)
* (c) 1999-2008 Kasper Skaarhoj (kasperYYYY@typo3.com)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
......
$arrValue = t3lib_div::array_merge_recursive_overrule($currentValueArray,$arrValue);
$xmlValue = $this->checkValue_flexArray2Xml($arrValue,TRUE);
}
// Action commands (sorting order and removals of elements)
$actionCMDs = t3lib_div::_GP('_ACTION_FLEX_FORMdata');
if (is_array($actionCMDs[$table][$id][$field]['data'])) {
......
* @return array Modified $res array
*/
function checkValue_inline($res,$value,$tcaFieldConf,$PP,$field) {
list($table,$id,$curValue,$status,$realPid,$recFID) = $PP;
list($table, $id, $curValue, $status, $realPid, $recFID) = $PP;
if (!$tcaFieldConf['foreign_table']) {
return false; // Fatal error, inline fields should always have a foreign_table defined
......
if(strpos($value, 'NEW') !== false || !t3lib_div::testInt($id)) {
$this->remapStackRecords[$table][$id] = array('remapStackIndex' => count($this->remapStack));
$this->remapStack[] = array(
'func' => 'checkValue_group_select_processDBdata',
'args' => array($valueArray,$tcaFieldConf,$id,$status,'inline',$table),
'pos' => array('valueArray' => 0, 'tcaFieldConf' => 1, 'id' => 2, 'table' => 5),
'func' => 'checkValue_inline_processDBdata',
'args' => array($valueArray, $tcaFieldConf, $id, $status, $table, $field),
'pos' => array('valueArray' => 0, 'tcaFieldConf' => 1, 'id' => 2, 'table' => 4),
'field' => $field
);
unset($res['value']);
} elseif($value || t3lib_div::testInt($id)) {
$newValueArray = $this->checkValue_group_select_processDBdata($valueArray,$tcaFieldConf,$id,$status,'inline', $table);
// Checking that the number of items is correct
$newVal = $this->checkValue_checkMax($tcaFieldConf, $newValueArray);
$res['value'] = implode(',',$newVal);
$res['value'] = $this->checkValue_inline_processDBdata($valueArray, $tcaFieldConf, $id, $status, $table, $field);
}
return $res;
......
$this->dbAnalysisStore[] = array($dbAnalysis,$tcaFieldConf['MM'],$id,$prep,$currentTable); // This will be traversed later to execute the actions
}
$valueArray = $dbAnalysis->countItems();
} elseif ($type == 'inline') {
if ($tcaFieldConf['foreign_field']) {
// if the record was imported, sorting was also imported, so skip this
$skipSorting = $this->callFromImpExp ? true : false;
// update record in intermediate table (sorting & pointer uid to parent record)
$dbAnalysis->writeForeignField($tcaFieldConf, $id, 0, $skipSorting);
$valueArray = $dbAnalysis->countItems();
} else {
$valueArray = $dbAnalysis->getValueArray($prep);
if ($prep) {
// @TODO: Do we want to support relations to multiple tables in Comma Separated Lists?
$valueArray = $dbAnalysis->convertPosNeg($valueArray,$tcaFieldConf['foreign_table'],$tcaFieldConf['neg_foreign_table']);
}
}
} else {
$valueArray = $dbAnalysis->getValueArray($prep);
if ($type=='select' && $prep) {
......
}
}
/**
* Returns data for inline fields.
*
* @param array Current value array
* @param array TCA field config
* @param integer Record id
* @param string Status string ('update' or 'new')
* @param string Table name, needs to be passed to t3lib_loadDBGroup
* @param string The current field the values are modified for
* @return string Modified values
*/
protected function checkValue_inline_processDBdata($valueArray, $tcaFieldConf, $id, $status, $table, $field) {
$newValue = '';
$foreignTable = $tcaFieldConf['foreign_table'];
/*
* Fetch the related child records by using t3lib_loadDBGroup:
* @var $dbAnalysis t3lib_loadDBGroup
*/
$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
$dbAnalysis->start(implode(',', $valueArray), $foreignTable, '', 0, $table, $tcaFieldConf);
// If the localizazionMode is set to 'keep', the children for the localized parent are kept as in the original untranslated record:
$localizationMode = t3lib_BEfunc::getInlineLocalizationMode($table, $tcaFieldConf);
if ($localizationMode=='keep' && $status=='update') {
// Fetch the current record and determine the original record:
$row = t3lib_BEfunc::getRecordWSOL($table, $id);
if (is_array($row)) {
$language = intval($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]);
$transOrigPointer = intval($row[$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']]);
// If language is set (e.g. 1) and also transOrigPointer (e.g. 123), use transOrigPointer as uid:
if ($language>0 && $transOrigPointer) {
$id = $transOrigPointer;
// If we're in active localizationMode 'keep', prevent from writing data to the field of the parent record:
// (on removing the localized parent, the original (untranslated) children would then also be removed)
$keepTranslation = true;
}
}
}
// IRRE with a pointer field (database normalization):
if ($tcaFieldConf['foreign_field']) {
// if the record was imported, sorting was also imported, so skip this
$skipSorting = ($this->callFromImpExp ? true : false);
// update record in intermediate table (sorting & pointer uid to parent record)
$dbAnalysis->writeForeignField($tcaFieldConf, $id, 0, $skipSorting);
$newValue = ($keepTranslation ? 0 : $dbAnalysis->countItems(false));
// IRRE with comma separated values:
} else {
$valueArray = $dbAnalysis->getValueArray();
// Checking that the number of items is correct:
$valueArray = $this->checkValue_checkMax($tcaFieldConf, $valueArray);
// If a valid translation of the 'keep' mode is active, update relations in the original(!) record:
if ($keepTranslation) {
$this->updateDB($table, $transOrigPointer, array($field => implode(',', $valueArray)));
} else {
$newValue = implode(',', $valueArray);
}
}
return $newValue;
}
......
/*********************************************
*
* PROCESSING COMMANDS
......
case 'localize':
$this->localize($table,$id,$value);
break;
case 'inlineLocalizeSynchronize':
$this->inlineLocalizeSynchronize($table, $id, $value);
break;
case 'version':
switch ((string)$value['action']) {
case 'new':
......
* @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
* @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!
* @param string Commalist of fields to exclude from the copy process (might get default values)
* @param integer Language ID (from sys_language table)
* @return integer ID of new record, if any
*/
function copyRecord($table,$uid,$destPid,$first=0,$overrideValues=array(),$excludeFields='') {
function copyRecord($table, $uid, $destPid, $first=0, $overrideValues=array(), $excludeFields='', $language=0) {
global $TCA;
$uid = $origUid = intval($uid);
......
$value = $this->getCopyHeader($table,$this->resolvePid($table,$destPid),$field,$this->clearPrefixFromValue($table,$value),0);
}
// Processing based on the TCA config field type (files, references, flexforms...)
$value = $this->copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf,$tscPID);
$value = $this->copyRecord_procBasedOnFieldType($table, $uid, $field, $value, $row, $conf, $tscPID, $language);
}
// Add value to array.
......
* @param array Record array
* @param array TCA field configuration
* @param integer Real page id (pid) the record is copied to
* @param integer Language ID (from sys_language table)
* @return mixed Processed value. Normally a string/integer, but can be an array for flexforms!
* @access private
* @see copyRecord()
*/
function copyRecord_procBasedOnFieldType($table,$uid,$field,$value,$row,$conf,$realDestPid) {
function copyRecord_procBasedOnFieldType($table, $uid, $field, $value, $row, $conf, $realDestPid, $language=0) {
global $TCA;
// 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)
......
if ($this->isReferenceField($conf) || $inlineSubType == 'mm') {
$allowedTables = $conf['type']=='group' ? $conf['allowed'] : $conf['foreign_table'].','.$conf['neg_foreign_table'];
$prependName = $conf['type']=='group' ? $conf['prepend_tname'] : $conf['neg_foreign_table'];
if ($conf['MM']) {
$localizeReferences = (isset($conf['foreign_table']) && t3lib_BEfunc::isTableLocalizable($conf['foreign_table']) && isset($conf['localizeReferencesAtParentLocalization']) && $conf['localizeReferencesAtParentLocalization']);
if ($conf['MM'] || $language>0 && $localizeReferences) {
$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
/* @var $dbAnalysis t3lib_loadDBGroup */
$dbAnalysis->start('', $allowedTables, $conf['MM'], $uid, $table, $conf);
$dbAnalysis->start($value, $allowedTables, $conf['MM'], $uid, $table, $conf);
if (!$conf['MM']) {
// Localize referenced records of select fields:
foreach ($dbAnalysis->itemArray as $index => $item) {
// Since select fields can reference many records, check whether there's already a localization:
$recordLocalization = t3lib_BEfunc::getRecordLocalization($item['table'], $item['id'], $language);
if (!$recordLocalization) {
$dbAnalysis->itemArray[$index]['id'] = $this->localize($item['table'], $item['id'], $language);
} else {
$dbAnalysis->itemArray[$index]['id'] = $recordLocalization[0]['uid'];
}
}
}
$value = implode(',',$dbAnalysis->getValueArray($prependName));
}
if ($value) { // Setting the value in this array will notify the remapListedDBRecords() function that this field MAY need references to be corrected
......
// If another inline subtype is used (comma-separated-values or the foreign_field property):
} elseif ($inlineSubType !== false) {
$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
/* @var $dbAnalysis t3lib_loadDBGroup */
$dbAnalysis->start($value, $conf['foreign_table'], '', $uid, $table, $conf);
// Get the localization mode for the current (parent) record (keep|select|all):
$localizazionMode = t3lib_BEfunc::getInlineLocalizationMode($table, $field);
// Localization in mode 'keep', isn't a real localization, but keeps the children of the original parent record:
if ($language>0 && $localizazionMode=='keep') {
$value = ($inlineSubType=='field' ? 0 : '');
// Execute copy or localization actions:
} else {
/*
* Fetch the related child records by using t3lib_loadDBGroup:
* @var $dbAnalysis t3lib_loadDBGroup
*/
$dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
$dbAnalysis->start($value, $conf['foreign_table'], '', $uid, $table, $conf);
// walk through the items, copy them and remember the new id
foreach ($dbAnalysis->itemArray as $k => $v) {
if (!t3lib_div::testInt($realDestPid)) {
$newId = $this->copyRecord($v['table'], $v['id'], -$v['id']);
} elseif ($realDestPid == -1) {
$newId = $this->versionizeRecord($v['table'], $v['id'], 'Auto-created for WS #'.$this->BE_USER->workspace);
} else {
$newId = $this->copyRecord_raw($v['table'], $v['id'], $realDestPid);
}
// Walk through the items, copy them and remember the new id:
foreach ($dbAnalysis->itemArray as $k => $v) {
// If language is set, this isn't a copy action but a localization of our parent/ancestor:
if ($language>0) {
// If children should be localized when the parent gets localized the first time, just do it:
if ($localizazionMode!=false && isset($conf['behaviour']['localizeChildrenAtParentLocalization']) && $conf['behaviour']['localizeChildrenAtParentLocalization']) {
$newId = $this->localize($v['table'], $v['id'], $language);
}
// If no language it set, this is a regular copy action:
} else {
if (!t3lib_div::testInt($realDestPid)) {
$newId = $this->copyRecord($v['table'], $v['id'], -$v['id']);
} elseif ($realDestPid == -1) {
$newId = $this->versionizeRecord($v['table'], $v['id'], 'Auto-created for WS #'.$this->BE_USER->workspace);
} else {
$newId = $this->copyRecord_raw($v['table'], $v['id'], $realDestPid);
}
}
// If the current field is set on a page record, update the pid of related child records:
if ($table == 'pages') {
$this->registerDBPids[$v['table']][$v['id']] = $uid;
// If the current field has ancestors that have a field on a page record, update the pid of related child records:
} elseif (isset($this->registerDBPids[$table][$uid])) {
$this->registerDBPids[$v['table']][$v['id']] = $this->registerDBPids[$table][$uid];
// If the current field is set on a page record, update the pid of related child records:
if ($table == 'pages') {
$this->registerDBPids[$v['table']][$v['id']] = $uid;
// If the current field has ancestors that have a field on a page record, update the pid of related child records:
} elseif (isset($this->registerDBPids[$table][$uid])) {
$this->registerDBPids[$v['table']][$v['id']] = $this->registerDBPids[$table][$uid];
}
$dbAnalysis->itemArray[$k]['id'] = $newId;
}
$dbAnalysis->itemArray[$k]['id'] = $newId;
// Store the new values, we will set up the uids for the subtype later on (exception keep localization from original record):
$value = implode(',',$dbAnalysis->getValueArray());
$this->registerDBList[$table][$uid][$field] = $value;
}
// store the new values, we will set up the uids for the subtype later on
$value = implode(',',$dbAnalysis->getValueArray());
$this->registerDBList[$table][$uid][$field] = $value;
}
// 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())
......
* @param string Table name
* @param integer Record uid (to be localized)
* @param integer Language ID (from sys_language table)
* @return void
* @return mixed The uid (integer) of the new translated record or false (boolean) if something went wrong
*/
function localize($table,$uid,$language) {
function localize($table, $uid, $language) {
global $TCA;
$newId = false;
$uid = intval($uid);
if ($TCA[$table] && $uid) {
......
$Ttable = 'pages_language_overlay';
t3lib_div::loadTCA($Ttable);
} else {
$pass = !t3lib_BEfunc::getRecordsByField($table,$TCA[$table]['ctrl']['transOrigPointerField'],$uid,'AND pid='.intval($row['pid']).' AND '.$TCA[$table]['ctrl']['languageField'].'='.intval($langRec['uid']));
$pass = !t3lib_BEfunc::getRecordLocalization($table, $uid, $langRec['uid'], 'AND pid='.intval($row['pid']));
$Ttable = $table;
}
......
if ($Ttable === $table) {
// Execute the copy:
$this->copyRecord($table,$uid,-$uid,1,$overrideValues,implode(',',$excludeFields));
$newId = $this->copyRecord($table, $uid, -$uid, 1, $overrideValues, implode(',', $excludeFields), $language);
} else {
// Create new record:
......
if ($theNewSQLID) {
// 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"
$this->copyMappingArray[$Ttable][$uid] = $theNewSQLID;
$newId = $theNewSQLID;
}
}
} else $this->newlog('Localization failed; There already was a localization for this language of the record!',1);
......
} 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.
(3-3/4)