Cleanup of the way objects are displayed/edited: DisplayBareProperties is now used for displaying (i.e. read-only) or modifying/creating an object. The means that:

1) the display/edition can be customized by overloading this method
2) the plug-ins's method OnDisplayProperties is now called in edition as well

A new class of template is introduced for building custom object displays: ObjectDetailsTemplate.

SVN:trunk[1429]
This commit is contained in:
Denis Flaven
2011-08-07 08:12:07 +00:00
parent eab1060f8e
commit 435d943f47
6 changed files with 310 additions and 235 deletions

View File

@@ -204,9 +204,9 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
$oBlock->Display($oPage, -1);
}
function DisplayBareProperties(WebPage $oPage, $bEditMode = false)
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '')
{
$oPage->add($this->GetBareProperties($oPage, $bEditMode));
$aFieldsMap = $this->GetBareProperties($oPage, $bEditMode, $sPrefix);
// Special case to display the case log, if any...
// WARNING: if you modify the loop below, also check the corresponding code in UpdateObject and DisplayModifyForm
@@ -214,7 +214,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
{
if ($oAttDef instanceof AttributeCaseLog)
{
$this->DisplayCaseLog($oPage, $sAttCode, '', '', false);
$this->DisplayCaseLog($oPage, $sAttCode, '', '', $bEditMode);
}
}
@@ -222,6 +222,8 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
{
$oExtensionInstance->OnDisplayProperties($this, $oPage, $bEditMode);
}
return $aFieldsMap;
}
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
@@ -382,7 +384,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
}
}
function GetBareProperties(WebPage $oPage, $bEditMode = false)
function GetBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix)
{
$sHtml = '';
$oAppContext = new ApplicationContext();
@@ -396,6 +398,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
$sHtml = '';
$aDetails = array();
$iInputId = 0;
$aFieldsMap = array();
foreach($aDetailsStruct as $sTab => $aCols )
{
$aDetails[$sTab] = array();
@@ -436,28 +439,94 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
}
foreach($aFields as $sAttCode)
{
$val = $this->GetFieldAsHtml($sClass, $sAttCode, $sStateAttCode);
if ($bEditMode)
{
$sComments = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : ' ';
$sInfos = ' ';
$iFlags = $this->GetAttributeFlags($sAttCode);
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ( (!$oAttDef->IsLinkSet()) && (($iFlags & OPT_ATT_HIDDEN) == 0))
{
if ($oAttDef->IsWritable())
{
if ($sStateAttCode == $sAttCode)
{
// State attribute is always read-only from the UI
$sHTMLValue = $this->GetStateLabel();
$val = array('label' => '<span>'.$oAttDef->GetLabel().'</span>', 'value' => $sHTMLValue, 'comments' => $sComments, 'infos' => $sInfos);
}
else
{
$sInputId = $this->m_iFormId.'_'.$sAttCode;
if ($iFlags & OPT_ATT_HIDDEN)
{
// Attribute is hidden, add a hidden input
$oPage->add('<input type="hidden" id="'.$sInputId.'" name="attr_'.$sPrefix.$sAttCode.'" value="'.htmlentities($this->Get($sAttCode), ENT_QUOTES, 'UTF-8').'"/>');
$aFieldsMap[$sAttCode] = $sInputId;
}
else
{
if ($iFlags & (OPT_ATT_READONLY|OPT_ATT_SLAVE))
{
// Check if the attribute is not read-only because of a synchro...
$aReasons = array();
$sSynchroIcon = '';
if ($iFlags & OPT_ATT_SLAVE)
{
$iSynchroFlags = $this->GetSynchroReplicaFlags($sAttCode, $aReasons);
$sSynchroIcon = "&nbsp;<img id=\"synchro_$sInputId\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
$sTip = '';
foreach($aReasons as $aRow)
{
$sTip .= "<p>Synchronized with {$aRow['name']} - {$aRow['description']}</p>";
}
$oPage->add_ready_script("$('#synchro_$sInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
}
// Attribute is read-only
$sHTMLValue = $this->GetAsHTML($sAttCode);
$sHTMLValue .= '<input type="hidden" id="'.$sInputId.'" name="attr_'.$sPrefix.$sAttCode.'" value="'.htmlentities($this->Get($sAttCode), ENT_QUOTES, 'UTF-8').'"/>';
$aFieldsMap[$sAttCode] = $sInputId;
$sComments = $sSynchroIcon;
}
else
{
$sValue = $this->Get($sAttCode);
$sDisplayValue = $this->GetEditValue($sAttCode);
$aArgs = array('this' => $this, 'formPrefix' => $sPrefix);
$sHTMLValue = "<span id=\"field_{$sInputId}\">".self::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sInputId, '', $iFlags, $aArgs).'</span>';
$aFieldsMap[$sAttCode] = $sInputId;
}
$val = array('label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().'</span>', 'value' => $sHTMLValue, 'comments' => $sComments, 'infos' => $sInfos);
}
}
}
else
{
$val = array('label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().'</span>', 'value' => $this->GetAsHTML($sAttCode), 'comments' => $sComments, 'infos' => $sInfos);
}
}
else
{
$val = null; // Skip this field
}
}
else
{
// !bEditMode
$val = $this->GetFieldAsHtml($sClass, $sAttCode, $sStateAttCode);
}
if ($val != null)
{
/*
* Removed for now...
// Check if the attribute is not mastered by a synchro...
$aReasons = array();
$iSynchroFlags = $this->GetSynchroReplicaFlags($sAttCode, $aReasons);
$sSynchroIcon = '';
if ($iSynchroFlags & OPT_ATT_SLAVE)
{
$sSynchroIcon = "&nbsp;<img id=\"synchro_$iInputId\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
$sTip = '';
foreach($aReasons as $aRow)
{
$sTip .= "<p>Synchronized with {$aRow['name']} - {$aRow['description']}</p>";
}
$oPage->add_ready_script("$('#synchro_$iInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
}
$val['comments'] = $sSynchroIcon;
*/
// The field is visible, add it to the current column
$aDetails[$sTab][$sColIndex][] = $val;
$iInputId++;
@@ -478,7 +547,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
}
$oPage->add('</tr></table>');
}
return $sHtml;
return $aFieldsMap;
}
@@ -1606,174 +1675,65 @@ EOF
{
$sFormAction = $aExtraParams['action'];
}
// Custom label for the apply button ?
if (isset($aExtraParams['custom_button']))
{
$sApplyButton = $aExtraParams['custom_button'];
}
else if ($iKey > 0)
{
$sApplyButton = Dict::S('UI:Button:Apply');
}
else
{
$sApplyButton = Dict::S('UI:Button:Create');
}
// Custom operation for the form ?
if (isset($aExtraParams['custom_operation']))
{
$sOperation = $aExtraParams['custom_operation'];
}
else if ($iKey > 0)
{
$sOperation = 'apply_modify';
}
else
{
$sOperation = 'apply_new';
}
if ($iKey > 0)
{
// The object already exists in the database, it's a modification
$sButtons = "<input type=\"hidden\" name=\"id\" value=\"$iKey\">\n";
$sButtons .= "<input type=\"hidden\" name=\"operation\" value=\"{$sOperation}\">\n";
$sButtons .= "<button type=\"button\" class=\"action cancel\"><span>".Dict::S('UI:Button:Cancel')."</span></button>&nbsp;&nbsp;&nbsp;&nbsp;\n";
$sButtons .= "<button type=\"submit\" class=\"action\"><span>{$sApplyButton}</span></button>\n";
}
else
{
// The object does not exist in the database it's a creation
$sButtons = "<input type=\"hidden\" name=\"operation\" value=\"$sOperation\">\n";
$sButtons .= "<button type=\"button\" class=\"action cancel\">".Dict::S('UI:Button:Cancel')."</button>&nbsp;&nbsp;&nbsp;&nbsp;\n";
$sButtons .= "<button type=\"submit\" class=\"action\"><span>{$sApplyButton}</span></button>\n";
}
$bDisplayActionsAtTop = MetaModel::GetConfig()->Get('display_actions_at_top');
$iTransactionId = utils::GetNewTransactionId();
$oPage->SetTransactionId($iTransactionId);
$oPage->add("<form action=\"$sFormAction\" id=\"form_{$this->m_iFormId}\" enctype=\"multipart/form-data\" method=\"post\" onSubmit=\"return OnSubmit('form_{$this->m_iFormId}');\">\n");
$oPage->add_ready_script("$(window).unload(function() { OnUnload('$iTransactionId') } );\n");
if ($bDisplayActionsAtTop)
{
$oPage->add($sButtons);
}
$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB, $sPrefix);
$oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB);
$oPage->SetCurrentTab(Dict::S('UI:PropertiesTab'));
// $aDetailsList = $this->FLattenZList(MetaModel::GetZListItems($sClass, 'details'));
//$aFullList = MetaModel::ListAttributeDefs($sClass);
$aList = array();
// Compute the list of properties to display, first the attributes in the 'details' list, then
// all the remaining attributes that are not external fields
// foreach($aDetailsList as $sAttCode)
// {
// $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
// if (!$oAttDef->IsExternalField())
// {
// $aList[] = $sAttCode;
// }
// }
$aDetailsList = MetaModel::GetZListItems($sClass, 'details');
$aDetailsStruct = self::ProcessZlist($aDetailsList, array('UI:PropertiesTab' => array()), 'UI:PropertiesTab', 'col1', '');
$sHtml = '';
$aDetails = array();
foreach($aDetailsStruct as $sTab => $aCols )
{
$aDetails[$sTab] = array();
ksort($aCols);
$oPage->SetCurrentTab(Dict::S($sTab));
$oPage->add('<table style="vertical-align:top"><tr>');
foreach($aCols as $sColIndex => $aFieldsets)
{
$sLabel = '';
$sPreviousLabel = '';
$aDetails[$sTab][$sColIndex] = array();
$oPage->add('<td style="vertical-align:top">');
//$aDetails[$sTab][$sColIndex] = array();
foreach($aFieldsets as $sFieldsetName => $aFields)
{
if (!empty($sFieldsetName) && ($sFieldsetName[0]!='_'))
{
$sLabel = $sFieldsetName;
}
else
{
$sLabel = '';
}
if ($sLabel != $sPreviousLabel)
{
if (!empty($sPreviousLabel))
{
$oPage->add('<fieldset>');
$oPage->add('<legend>'.Dict::S($sPreviousLabel).'</legend>');
}
$oPage->Details($aDetails[$sTab][$sColIndex]);
if (!empty($sPreviousLabel))
{
$oPage->add('</fieldset>');
}
$aDetails[$sTab][$sColIndex] = array();
$sPreviousLabel = $sLabel;
}
foreach($aFields as $sAttCode)
{
$aVal = null;
$sComments = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : '&nbsp;';
$sInfos = '&nbsp;';
$iFlags = $this->GetAttributeFlags($sAttCode);
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ( (!$oAttDef->IsLinkSet()) && (($iFlags & OPT_ATT_HIDDEN) == 0))
{
if ($oAttDef->IsWritable())
{
if ($sStateAttCode == $sAttCode)
{
// State attribute is always read-only from the UI
$sHTMLValue = $this->GetStateLabel();
$aVal = array('label' => '<span>'.$oAttDef->GetLabel().'</span>', 'value' => $sHTMLValue, 'comments' => $sComments, 'infos' => $sInfos);
}
else
{
$sInputId = $this->m_iFormId.'_'.$sAttCode;
if ($iFlags & OPT_ATT_HIDDEN)
{
// Attribute is hidden, add a hidden input
$oPage->add('<input type="hidden" id="'.$sInputId.'" name="attr_'.$sPrefix.$sAttCode.'" value="'.htmlentities($this->Get($sAttCode), ENT_QUOTES, 'UTF-8').'"/>');
$aFieldsMap[$sAttCode] = $sInputId;
}
else
{
if ($iFlags & (OPT_ATT_READONLY|OPT_ATT_SLAVE))
{
// Check if the attribute is not read-only because of a synchro...
$aReasons = array();
$sSynchroIcon = '';
if ($iFlags & OPT_ATT_SLAVE)
{
$iSynchroFlags = $this->GetSynchroReplicaFlags($sAttCode, $aReasons);
$sSynchroIcon = "&nbsp;<img id=\"synchro_$sInputId\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
$sTip = '';
foreach($aReasons as $aRow)
{
$sTip .= "<p>Synchronized with {$aRow['name']} - {$aRow['description']}</p>";
}
$oPage->add_ready_script("$('#synchro_$sInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
}
// Attribute is read-only
$sHTMLValue = $this->GetAsHTML($sAttCode);
$sHTMLValue .= '<input type="hidden" id="'.$sInputId.'" name="attr_'.$sPrefix.$sAttCode.'" value="'.htmlentities($this->Get($sAttCode), ENT_QUOTES, 'UTF-8').'"/>';
$aFieldsMap[$sAttCode] = $sInputId;
$sComments = $sSynchroIcon;
}
else
{
$sValue = $this->Get($sAttCode);
$sDisplayValue = $this->GetEditValue($sAttCode);
$aArgs = array('this' => $this, 'formPrefix' => $sPrefix);
$sHTMLValue = "<span id=\"field_{$sInputId}\">".self::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sInputId, '', $iFlags, $aArgs).'</span>';
$aFieldsMap[$sAttCode] = $sInputId;
}
$aVal = array('label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().'</span>', 'value' => $sHTMLValue, 'comments' => $sComments, 'infos' => $sInfos);
}
}
}
else
{
$aVal = array('label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().'</span>', 'value' => $this->GetAsHTML($sAttCode), 'comments' => $sComments, 'infos' => $sInfos);
}
}
if ($aVal != null)
{
// The field is visible, add it to the current column
$aDetails[$sTab][$sColIndex][] = $aVal;
}
}
}
if (!empty($sPreviousLabel))
{
$oPage->add('<fieldset>');
$oPage->add('<legend>'.Dict::S($sPreviousLabel).'</legend>');
}
$oPage->Details($aDetails[$sTab][$sColIndex]);
if (!empty($sPreviousLabel))
{
$oPage->add('</fieldset>');
}
$oPage->add('</td>');
}
$oPage->add('</tr></table>');
}
// Special case to display the case log, if any...
// WARNING: if you modify the loop below, also check the corresponding code in UpdateObject and DisplayDetails
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
if ($oAttDef instanceof AttributeCaseLog)
{
$sComments = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : '&nbsp;';
$this->DisplayCaseLog($oPage, $sAttCode, $sComments, $sPrefix, true);
$sInputId = $this->m_iFormId.'_'.$sAttCode;
$aFieldsMap[$sAttCode] = $sInputId;
}
}
$aFieldsMap = $this->DisplayBareProperties($oPage, true, $sPrefix);
// Now display the relations, one tab per relation
if (!isset($aExtraParams['noRelations']))
{
@@ -1788,49 +1748,11 @@ EOF
$oPage->add("<input type=\"hidden\" name=\"$sName\" value=\"$value\">\n");
}
$oPage->add($oAppContext->GetForForm());
// Custom operation for the form ?
if (isset($aExtraParams['custom_operation']))
if ($bDisplayActionsAtTop)
{
$sOperation = $aExtraParams['custom_operation'];
}
else if ($iKey > 0)
{
$sOperation = 'apply_modify';
}
else
{
$sOperation = 'apply_new';
$oPage->add($sButtons);
}
// Custom label for the apply button ?
if (isset($aExtraParams['custom_button']))
{
$sApplyButton = $aExtraParams['custom_button'];
}
else if ($iKey > 0)
{
$sApplyButton = Dict::S('UI:Button:Apply');
}
else
{
$sApplyButton = Dict::S('UI:Button:Create');
}
if ($iKey > 0)
{
// The object already exists in the database, it's a modification
$oPage->add("<input type=\"hidden\" name=\"id\" value=\"$iKey\">\n");
$oPage->add("<input type=\"hidden\" name=\"operation\" value=\"{$sOperation}\">\n");
$oPage->add("<button type=\"button\" class=\"action cancel\"><span>".Dict::S('UI:Button:Cancel')."</span></button>&nbsp;&nbsp;&nbsp;&nbsp;\n");
$oPage->add("<button type=\"submit\" class=\"action\"><span>{$sApplyButton}</span></button>\n");
}
else
{
// The object does not exist in the database it's a creation
$oPage->add("<input type=\"hidden\" name=\"operation\" value=\"$sOperation\">\n");
$oPage->add("<button type=\"button\" class=\"action cancel\">".Dict::S('UI:Button:Cancel')."</button>&nbsp;&nbsp;&nbsp;&nbsp;\n");
$oPage->add("<button type=\"submit\" class=\"action\"><span>{$sApplyButton}</span></button>\n");
}
// Hook the cancel button via jQuery so that it can be unhooked easily as well if needed
$sDefaultUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=cancel&'.$oAppContext->GetForLink();
$oPage->add_ready_script("$('#form_{$this->m_iFormId} button.cancel').click( function() { BackToDetails('$sClass', $iKey, '$sDefaultUrl')} );");

View File

@@ -675,13 +675,6 @@ class DisplayBlock
$sHtml .= '<a class="summary" href="'.$sHyperlink.'">'.Dict::Format(str_replace('_', ':', $sLabel), $iCount).'</a>';
break;
case 'bare_details':
while($oObj = $this->m_oSet->Fetch())
{
$sHtml .= $oObj->GetBareProperties($oPage);
}
break;
case 'csv':
$sHtml .= "<textarea style=\"width:95%;height:98%\">\n";
$sHtml .= cmdbAbstractObject::GetSetAsCSV($this->m_oSet);

View File

@@ -888,6 +888,43 @@ EOF
}
}
/**
* Records the current state of the 'html' part of the page output
* @return mixed The current state of the 'html' output
*/
public function start_capture()
{
if (!empty($this->m_sCurrentTabContainer) && !empty($this->m_sCurrentTab))
{
$iOffset = isset($this->m_aTabs[$this->m_sCurrentTabContainer][$this->m_sCurrentTab]) ? strlen($this->m_aTabs[$this->m_sCurrentTabContainer][$this->m_sCurrentTab]): 0;
return array('tc' => $this->m_sCurrentTabContainer, 'tab' => $this->m_sCurrentTab, 'offset' => $iOffset);
}
else
{
parent::start_capture();
}
}
/**
* Returns the part of the html output that occurred since the call to start_capture
* and removes this part from the current html output
* @param $offset mixed The value returned by start_capture
* @return string The part of the html output that was added since the call to start_capture
*/
public function end_capture($offset)
{
if (is_array($offset))
{
$sCaptured = substr($this->m_aTabs[$offset['tc']][$offset['tab']], $offset['offset']);
$this->m_aTabs[$offset['tc']][$offset['tab']] = substr($this->m_aTabs[$offset['tc']][$offset['tab']], 0, $offset['offset']);
}
else
{
$sCaptured = parent::end_capture($offset);
}
return $sCaptured;
}
/**
* Set the message to be displayed in the 'admin-banner' section at the top of the page
*/

View File

@@ -233,7 +233,6 @@ class DisplayTemplate
<itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = \'$class$\'</itopblock>
</div>
<img src="../../images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
<itopblock blockclass="DisplayBlock" asynchronous="false" type="bare_details" encoding="text/oql">SELECT NetworkDevice AS d WHERE d.id = $id$</itopblock>
<itoptabs>
<itoptab name="Interfaces">
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Interface AS i WHERE i.device_id = $id$</itopblock>
@@ -254,6 +253,92 @@ class DisplayTemplate
}
}
/**
* Special type of template for displaying the details of an object
* On top of the defaut 'blocks' managed by the parent class, the following placeholders
* are available in such a template:
* $attribute_code$ An attribute of the object (in edit mode this is the input for the attribute)
* $attribute_code->label()$ The label of an attribute
* $PlugIn:plugInClass->properties()$ The ouput of OnDisplayProperties of the specified plugInClass
*/
class ObjectDetailsTemplate extends DisplayTemplate
{
public function __construct($sTemplate, $oObj, $sFormPrefix = '')
{
parent::__construct($sTemplate);
$this->m_oObj = $oObj;
$this->m_sPrefix = $sFormPrefix;
}
public function Render(WebPage $oPage, $aParams = array(), $bEditMode = false)
{
$aTemplateFields = array();
preg_match_all('/\\$([a-z0-9_]+)\\$/', $this->m_sTemplate, $aMatches);
$aTemplateFields = $aMatches[1];
$aFieldsMap = array();
$sClass = get_class($this->m_oObj);
// Renders the fields used in the template
foreach(MetaModel::ListAttributeDefs(get_class($this->m_oObj)) as $sAttCode => $oAttDef)
{
$aParams[$sAttCode.'->label()'] = $oAttDef->GetLabel();
$iInputId = 'Z_'.$sAttCode; // TODO: generate a real/unique prefix...
if (in_array($sAttCode, $aTemplateFields))
{
$iFlags = $this->m_oObj->GetAttributeFlags($sAttCode);
if ($iFlags & OPT_ATT_HIDDEN)
{
$aParams[$sAttCode.'->label()'] = '';
$aParams[$sAttCode] = '';
}
elseif ($bEditMode && !($iFlags && OPT_ATT_READONLY)) //TODO: check the data synchro status...
{
$aParams[$sAttCode] = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef,
$this->m_oObj->Get($sAttCode),
$this->m_oObj->GetEditValue($sAttCode),
$iInputId, // InputID
'',
$iFlags,
array('this' => $this->m_oObj) // aArgs
).'</span>';
$aFieldsMap[$sAttCode] = $iInputId;
}
else
{
$aParams[$sAttCode] = $this->m_oObj->GetAsHTML($sAttCode);
}
}
}
// Renders the PlugIns used in the template
preg_match_all('/\\$PlugIn:([A-Za-z0-9_]+)->properties\\(\\)\\$/', $this->m_sTemplate, $aMatches);
$aPlugInProperties = $aMatches[1];
foreach($aPlugInProperties as $sPlugInClass)
{
$oInstance = MetaModel::GetPlugins('iApplicationUIExtension', $sPlugInClass);
if ($oInstance != null) // Safety check...
{
$offset = $oPage->start_capture();
$oInstance->OnDisplayProperties($this->m_oObj, $oPage, $bEditMode);
$sContent = $oPage->end_capture($offset);
$aParams["PlugIn:{$sPlugInClass}->properties()"]= $sContent;
}
else
{
$aParams["PlugIn:{$sPlugInClass}->properties()"]= "Missing PlugIn: $sPlugInClass";
}
}
$offset = $oPage->start_capture();
parent::Render($oPage, $aParams);
$sContent = $oPage->end_capture($offset);
// Remove empty table rows in case some attributes are hidden...
$sContent = preg_replace('/<tr[^>]*>\s*(<td[^>]*>\s*<\\/td>)+\s*<\\/tr>/im', '', $sContent);
$oPage->add($sContent);
return $aFieldsMap;
}
}
//DisplayTemplate::UnitTest();
?>

View File

@@ -246,6 +246,28 @@ class WebPage
$this->add($this->GetDetails($aFields));
}
/**
* Records the current state of the 'html' part of the page output
* @return mixed The current state of the 'html' output
*/
public function start_capture()
{
return strlen($this->s_content);
}
/**
* Returns the part of the html output that occurred since the call to start_capture
* and removes this part from the current html output
* @param $offset mixed The value returned by start_capture
* @return string The part of the html output that was added since the call to start_capture
*/
public function end_capture($offset)
{
$sCaptured = substr($this->s_content, $offset);
$this->s_content = substr($this->s_content, 0, $offset);
return $sCaptured;
}
/**
* Build a special kind of TABLE useful for displaying the details of an object from a hash array of data
@@ -302,7 +324,7 @@ class WebPage
{
$sSelected = ($value == $key) ? ' checked' : '';
}
$sHTMLValue .= "<input type=\"radio\" id=\"{$iId}_{$key}\" name=\"attr_radio_$sFieldName\" onChange=\"$('#{$iId}').val(this.value).trigger('change');\" value=\"$key\"$sSelected><label class=\"radio\" for=\"{$iId}_{$key}\">&nbsp;$display_value</label>&nbsp;";
$sHTMLValue .= "<input type=\"radio\" id=\"{$iId}_{$key}\" name=\"radio_$sFieldName\" onChange=\"$('#{$iId}').val(this.value).trigger('change');\" value=\"$key\"$sSelected><label class=\"radio\" for=\"{$iId}_{$key}\">&nbsp;$display_value</label>&nbsp;";
if ($bVertical)
{
if ($idx == 0)
@@ -314,7 +336,7 @@ class WebPage
}
$idx++;
}
$sHTMLValue .= "<input type=\"hidden\" id=\"$iId\" name=\"attr_$sFieldName\" value=\"$value\"/>";
$sHTMLValue .= "<input type=\"hidden\" id=\"$iId\" name=\"$sFieldName\" value=\"$value\"/>";
if (!$bVertical)
{
// Validation icon at the end of the line

View File

@@ -1332,7 +1332,7 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
{
$oExtensionInstance = new $sPHPClass;
}
self::$m_aExtensionClasses[$sInterface][] = $oExtensionInstance;
self::$m_aExtensionClasses[$sInterface][$sPHPClass] = $oExtensionInstance;
}
}
}
@@ -4457,6 +4457,22 @@ if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
}
}
/**
* Returns the instance of the specified plug-ins for the given interface
*/
public static function GetPlugins($sInterface, $sClassName)
{
$oInstance = null;
if (array_key_exists($sInterface, self::$m_aExtensionClasses))
{
if (array_key_exists($sClassName, self::$m_aExtensionClasses[$sInterface]))
{
return self::$m_aExtensionClasses[$sInterface][$sClassName];
}
}
return $oInstance;
}
public static function GetCacheEntries(Config $oConfig = null)
{
if (!function_exists('apc_cache_info')) return array();