- Implementing the creation of objects on the fly when editing an extrernal key... still to be fully tested.

SVN:trunk[955]
This commit is contained in:
Denis Flaven
2010-11-22 10:44:43 +00:00
parent d098bae484
commit 0306c6691a
9 changed files with 501 additions and 51 deletions

View File

@@ -33,6 +33,9 @@ class ajax_page extends WebPage
* @var Hash
*/
protected $m_sReadyScript;
protected $m_sCurrentTab;
protected $m_sCurrentTabContainer;
protected $m_aTabs;
/**
* constructor for the web page
@@ -44,8 +47,44 @@ class ajax_page extends WebPage
$this->m_sReadyScript = "";
$this->add_header("Content-type: text/html; charset=utf-8");
$this->add_header("Cache-control: no-cache");
$this->m_sCurrentTabContainer = '';
$this->m_sCurrentTab = '';
$this->m_aTabs = array();
}
public function AddTabContainer($sTabContainer, $sPrefix = '')
{
$this->m_aTabs[$sTabContainer] = array('content' =>'', 'prefix' => $sPrefix);
$this->add("\$Tabs:$sTabContainer\$");
}
public function AddToTab($sTabContainer, $sTabLabel, $sHtml)
{
if (!isset($this->m_aTabs[$sTabContainer]['content'][$sTabLabel]))
{
// Set the content of the tab
$this->m_aTabs[$sTabContainer]['content'][$sTabLabel] = $sHtml;
}
else
{
// Append to the content of the tab
$this->m_aTabs[$sTabContainer]['content'][$sTabLabel] .= $sHtml;
}
}
public function SetCurrentTabContainer($sTabContainer = '')
{
$sPreviousTabContainer = $this->m_sCurrentTabContainer;
$this->m_sCurrentTabContainer = $sTabContainer;
return $sPreviousTabContainer;
}
public function SetCurrentTab($sTabLabel = '')
{
$sPreviousTab = $this->m_sCurrentTab;
$this->m_sCurrentTab = $sTabLabel;
return $sPreviousTab;
}
/**
* Echoes the content of the whole page
@@ -57,15 +96,88 @@ class ajax_page extends WebPage
{
header($s_header);
}
if (count($this->m_aTabs) > 0)
{
$this->add_ready_script(
<<<EOF
// The "tab widgets" to handle.
var tabs = $('div[id^=tabbedContent]');
// This selector will be reused when selecting actual tab widget A elements.
var tab_a_selector = 'ul.ui-tabs-nav a';
// Enable tabs on all tab widgets. The `event` property must be overridden so
// that the tabs aren't changed on click, and any custom event name can be
// specified. Note that if you define a callback for the 'select' event, it
// will be executed for the selected tab whenever the hash changes.
tabs.tabs({ event: 'change' });
// Define our own click handler for the tabs, overriding the default.
tabs.find( tab_a_selector ).click(function()
{
var state = {};
// Get the id of this tab widget.
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
// Get the index of this tab.
var idx = $(this).parent().prevAll().length;
// Set the state!
state[ id ] = idx;
$.bbq.pushState( state );
});
EOF
);
}
// Render the tabs in the page (if any)
foreach($this->m_aTabs as $sTabContainerName => $aTabContainer)
{
$sTabs = '';
$m_aTabs = $aTabContainer['content'];
$sPrefix = $aTabContainer['prefix'];
$container_index = 0;
if (count($m_aTabs) > 0)
{
$sTabs = "<!-- tabs -->\n<div id=\"tabbedContent_{$sPrefix}{$container_index}\" class=\"light\">\n";
$sTabs .= "<ul>\n";
// Display the unordered list that will be rendered as the tabs
$i = 0;
foreach($m_aTabs as $sTabName => $sTabContent)
{
$sTabs .= "<li><a href=\"#tab_{$sPrefix}$i\" class=\"tab\"><span>".htmlentities($sTabName, ENT_QUOTES, 'UTF-8')."</span></a></li>\n";
$i++;
}
$sTabs .= "</ul>\n";
// Now add the content of the tabs themselves
$i = 0;
foreach($m_aTabs as $sTabName => $sTabContent)
{
$sTabs .= "<div id=\"tab_{$sPrefix}$i\">".$sTabContent."</div>\n";
$i++;
}
$sTabs .= "</div>\n<!-- end of tabs-->\n";
}
$this->s_content = str_replace("\$Tabs:$sTabContainerName\$", $sTabs, $this->s_content);
$container_index++;
}
$s_captured_output = ob_get_contents();
ob_end_clean();
echo $this->s_content;
echo $this->s_deferred_content;
if (count($this->a_scripts) > 0)
{
echo "<script type=\"text/javascript\">\n";
echo implode("\n", $this->a_scripts);
echo "\n</script>\n";
}
if (!empty($this->m_sReadyScript))
{
echo "<script>\n";
echo "<script type=\"text/javascript\">\n";
echo $this->m_sReadyScript; // Ready Scripts are output as simple scripts
echo "</script>\n";
echo "\n</script>\n";
}
if (trim($s_captured_output) != "")
{
@@ -82,6 +194,18 @@ class ajax_page extends WebPage
public function small_p($sText)
{
}
public function add($sHtml)
{
if (!empty($this->m_sCurrentTabContainer) && !empty($this->m_sCurrentTab))
{
$this->AddToTab($this->m_sCurrentTabContainer, $this->m_sCurrentTab, $sHtml);
}
else
{
parent::add($sHtml);
}
}
/**
* Adds a script to be executed when the DOM is ready (typical JQuery use)

View File

@@ -1032,10 +1032,9 @@ EOF
{
static $iInputId = 0;
$sFieldPrefix = '';
if (isset($aArgs['prefix']))
{
$sFieldPrefix = $aArgs['prefix'];
}
$sFormPrefix = isset($aArgs['formPrefix']) ? $aArgs['formPrefix'] : '';
$sFieldPrefix = isset($aArgs['prefix']) ? $sFormPrefix.$aArgs['prefix'] : $sFormPrefix;
if (isset($aArgs[$sAttCode]) && empty($value))
{
// default value passed by the context (either the app context of the operation)
@@ -1136,7 +1135,7 @@ EOF
if (count($aAllowedValues) >= $iMaxComboLength)
{
// too many choices, use an autocomplete
$oWidget = new UIAutoCompleteWidget($sAttCode, $sClass, $oAttDef->GetLabel(), $aAllowedValues, $value, $iId, $sNameSuffix, $sFieldPrefix);
$oWidget = new UIAutoCompleteWidget($sAttCode, $sClass, $oAttDef->GetLabel(), $aAllowedValues, $value, $iId, $sNameSuffix, $sFieldPrefix, $sFormPrefix);
$sHTMLValue = $oWidget->Display($oPage, $aArgs);
}
@@ -1206,12 +1205,12 @@ EOF
{
$sNullValue = "'$sNullValue'"; // Add quotes to turn this into a JS string if it's not a number
}
$oPage->add_ready_script("$('#$iId').bind('".implode(' ', $aEventsList)."', function(evt, sFormId) { return ValidateField('$iId', '$sPattern', $sMandatory, sFormId, $sNullValue) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#$iId').bind('".implode(' ', $aEventsList)."', function(evt, sFormId) { return ValidateField('$iId', '$sPattern', $sMandatory, sFormId, $sNullValue) } );\n"); // Bind to a custom event: validate
}
$aDependencies = MetaModel::GetDependentAttributes($sClass, $sAttCode); // List of attributes that depend on the current one
if (count($aDependencies) > 0)
{
$oPage->add_ready_script("$('#$iId').bind('change', function(evt, sFormId) { return UpdateDependentFields(['".implode("','", $aDependencies)."']) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#$iId').bind('change', function(evt, sFormId) { return oWizardHelper{$sFormPrefix}.UpdateDependentFields(['".implode("','", $aDependencies)."']) } );\n"); // Bind to a custom event: validate
}
}
return "<div>{$sHTMLValue}</div>";
@@ -1219,9 +1218,14 @@ EOF
public function DisplayModifyForm(WebPage $oPage, $aExtraParams = array())
{
static $iGlobalFormId = 0;
static $iGlobalFormId = 1;
$iGlobalFormId++;
$this->m_iFormId = $iGlobalFormId;
$sPrefix = '';
if (isset($aExtraParams['formPrefix']))
{
$sPrefix = $aExtraParams['formPrefix'];
}
$this->m_iFormId = $sPrefix.$iGlobalFormId;
$sClass = get_class($this);
$oAppContext = new ApplicationContext();
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
@@ -1238,7 +1242,7 @@ EOF
}
$oPage->add("<form action=\"$sFormAction\" id=\"form_{$this->m_iFormId}\" enctype=\"multipart/form-data\" method=\"post\" onSubmit=\"return CheckFields('form_{$this->m_iFormId}', true)\">\n");
$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB);
$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB, $sPrefix);
$oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB);
$oPage->SetCurrentTab(Dict::S('UI:PropertiesTab'));
// $aDetailsList = $this->FLattenZList(MetaModel::GetZListItems($sClass, 'details'));
@@ -1310,7 +1314,7 @@ EOF
{
$sValue = $this->Get($sAttCode);
$sDisplayValue = $this->GetEditValue($sAttCode);
$aArgs = array('this' => $this);
$aArgs = array('this' => $this, 'formPrefix' => $sPrefix);
$sInputId = $this->m_iFormId.'_'.$sAttCode;
$sHTMLValue = "<span id=\"field_{$sInputId}\">".self::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sInputId, '', $iFlags, $aArgs).'</span>';
$aFieldsMap[$sAttCode] = $sInputId;
@@ -1343,8 +1347,10 @@ EOF
}
// Now display the relations, one tab per relation
$this->DisplayBareRelations($oPage, true); // Edit mode
if (!isset($aExtraParams['noRelations']))
{
$this->DisplayBareRelations($oPage, true); // Edit mode
}
$oPage->SetCurrentTab('');
$oPage->add("<input type=\"hidden\" name=\"class\" value=\"$sClass\">\n");
@@ -1359,16 +1365,20 @@ EOF
// The object already exists in the database, it's modification
$oPage->add("<input type=\"hidden\" name=\"id\" value=\"$iKey\">\n");
$oPage->add("<input type=\"hidden\" name=\"operation\" value=\"apply_modify\">\n");
$oPage->add("<button type=\"button\" class=\"action\" onClick=\"BackToDetails('$sClass', $iKey)\"><span>".Dict::S('UI:Button:Cancel')."</span></button>&nbsp;&nbsp;&nbsp;&nbsp;\n");
// $oPage->add("<button type=\"button\" id=\"btn_cancel_{$sPrefix}\" class=\"action\" onClick=\"BackToDetails('$sClass', $iKey)\"><span>".Dict::S('UI:Button:Cancel')."</span></button>&nbsp;&nbsp;&nbsp;&nbsp;\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>".Dict::S('UI:Button:Apply')."</span></button>\n");
}
else
{
// The object does not exist in the database it's a creation
$oPage->add("<input type=\"hidden\" name=\"operation\" value=\"apply_new\">\n");
$oPage->add("<button type=\"button\" class=\"action\" onClick=\"BackToList('$sClass')\"><span>".Dict::S('UI:Button:Cancel')."</span></button>&nbsp;&nbsp;&nbsp;&nbsp;\n");
// $oPage->add("<button type=\"button\" id=\"btn_cancel_{$sPrefix}\" class=\"action\" onClick=\"BackToDetails('$sClass', $iKey)\"><span>".Dict::S('UI:Button:Cancel')."</span></button>&nbsp;&nbsp;&nbsp;&nbsp;\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>".Dict::S('UI:Button:Create')."</span></button>\n");
}
// Hook the cancel button via jQuery so that it can be unhooked easily as well if needed
$oPage->add_ready_script("$('#form_{$this->m_iFormId} button.cancel').click( function() { BackToDetails('$sClass', $iKey)} );");
$oPage->add("</form>\n");
$iFieldsCount = count($aFieldsMap);
@@ -1377,15 +1387,16 @@ EOF
$oPage->add_script(
<<<EOF
// Create the object once at the beginning of the page...
var oWizardHelper = new WizardHelper('$sClass');
oWizardHelper.SetFieldsMap($sJsonFieldsMap);
oWizardHelper.SetFieldsCount($iFieldsCount);
var oWizardHelper$sPrefix = new WizardHelper('$sClass', '$sPrefix');
oWizardHelper$sPrefix.SetFieldsMap($sJsonFieldsMap);
oWizardHelper$sPrefix.SetFieldsCount($iFieldsCount);
EOF
);
$oPage->add_ready_script(
<<<EOF
// Starts the validation when the page is ready
CheckFields('form_{$this->m_iFormId}', false);
EOF
);
}
@@ -1399,9 +1410,12 @@ EOF
if ($oObjectToClone == null)
{
$sTargetState = MetaModel::GetDefaultState($sClass);
$oObj = MetaModel::NewObject($sClass);
$oObj->Set($sStateAttCode, $sTargetState);
if (!empty($sStateAttCode))
{
$sTargetState = MetaModel::GetDefaultState($sClass);
$oObj->Set($sStateAttCode, $sTargetState);
}
}
else
{
@@ -1439,7 +1453,7 @@ EOF
}
}
}
return $oObj->DisplayModifyForm( $oPage, $aExtraParams = array());
return $oObj->DisplayModifyForm( $oPage, $aExtraParams);
}
protected static function ProcessZlist($aList, $aDetails, $sCurrentTab, $sCurrentCol, $sCurrentSet)
@@ -1663,5 +1677,100 @@ EOF
return $sContextParam;
}
}
/**
* Updates the object from the POSTed parameters
*/
function UpdateObject($sFormPrefix = '')
{
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef)
{
if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect())
{
$aLinks = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", '');
$sLinkedClass = $oAttDef->GetLinkedClass();
$sExtKeyToRemote = $oAttDef->GetExtKeyToRemote();
$sExtKeyToMe = $oAttDef->GetExtKeyToMe();
$oLinkedSet = DBObjectSet::FromScratch($sLinkedClass);
if (is_array($aLinks))
{
foreach($aLinks as $id => $aData)
{
if (is_numeric($id))
{
if ($id < 0)
{
// New link to be created, the opposite of the id (-$id) is the ID of the remote object
$oLink = MetaModel::NewObject($sLinkedClass);
$oLink->Set($sExtKeyToRemote, -$id);
$oLink->Set($sExtKeyToMe, $this->GetKey());
}
else
{
// Existing link, potentially to be updated...
$oLink = MetaModel::GetObject($sLinkedClass, $id);
}
// Now populate the attributes
foreach($aData as $sName => $value)
{
if (MetaModel::IsValidAttCode($sLinkedClass, $sName))
{
$oLinkAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sName);
if ($oLinkAttDef->IsWritable())
{
$oLink->Set($sName, $value);
}
}
}
$oLinkedSet->AddObject($oLink);
}
}
}
$this->Set($sAttCode, $oLinkedSet);
}
else if ($oAttDef->IsWritable())
{
$iFlags = $this->GetAttributeFlags($sAttCode);
if ($iFlags & (OPT_ATT_HIDDEN | OPT_ATT_READONLY))
{
// Non-visible, or read-only attribute, do nothing
}
elseif ($oAttDef->GetEditClass() == 'Document')
{
// There should be an uploaded file with the named attr_<attCode>
$oDocument = utils::ReadPostedDocument("file_{$sFormPrefix}{$sAttCode}");
if (!$oDocument->IsEmpty())
{
// A new file has been uploaded
$this->Set($sAttCode, $oDocument);
}
}
elseif ($oAttDef->GetEditClass() == 'One Way Password')
{
// Check if the password was typed/changed
$bChanged = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_changed", false);
if ($bChanged)
{
// The password has been changed or set
$rawValue = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null);
$this->Set($sAttCode, $rawValue);
}
}
else
{
$rawValue = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null);
if (!is_null($rawValue))
{
$aAttributes[$sAttCode] = trim($rawValue);
$previousValue = $this->Get($sAttCode);
if ($previousValue !== $aAttributes[$sAttCode])
{
$this->Set($sAttCode, $aAttributes[$sAttCode]);
}
}
}
}
}
}
}
?>

View File

@@ -69,7 +69,7 @@ class UIAutoCompleteWidget
protected $iId;
protected $sTitle;
public function __construct($sAttCode, $sClass, $sTitle, $aAllowedValues, $value, $iInputId, $sNameSuffix = '', $sFieldPrefix = '')
public function __construct($sAttCode, $sClass, $sTitle, $aAllowedValues, $value, $iInputId, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
{
self::$iWidgetIndex++;
$this->sAttCode = $sAttCode;
@@ -82,6 +82,7 @@ class UIAutoCompleteWidget
$this->sFieldPrefix = $sFieldPrefix;
$this->sTargetClass = $this->oAttDef->GetTargetClass();
$this->sTitle = $sTitle;
$this->sFormPrefix = $sFormPrefix;
}
/**
@@ -100,17 +101,25 @@ class UIAutoCompleteWidget
{
$sDisplayValue = $this->GetObjectName($this->value);
}
$bCreate = UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY);
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sFormPrefix = $this->sFormPrefix;
$oPage->add_ready_script(
<<<EOF
oACWidget_{$this->iId} = new AutocompleteWidget('$this->iId', '$this->sClass', '$this->sAttCode', '$this->sNameSuffix');
oACWidget_{$this->iId} = new AutocompleteWidget('$this->iId', '$this->sClass', '$this->sAttCode', '$this->sNameSuffix', oWizardHelper$sFormPrefix);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
EOF
);
$iMinChars = $this->oAttDef->GetMinAutoCompleteChars();
// the input for the auto-complete
$sHTMLValue = "<input count=\"".count($this->aAllowedValues)."\" type=\"text\" id=\"label_$this->iId\" size=\"30\" maxlength=\"$iFieldSize\" value=\"$sDisplayValue\"/>&nbsp;<a class=\"no-arrow\" href=\"javascript:oACWidget_{$this->iId}.Search();\"><img style=\"border:0;vertical-align:middle;\" src=\"../images/mini_search.gif\" /></a>&nbsp;<span id=\"v_{$this->iId}\"></span>";
$sHTMLValue = "<input count=\"".count($this->aAllowedValues)."\" type=\"text\" id=\"label_$this->iId\" size=\"30\" maxlength=\"$iFieldSize\" value=\"$sDisplayValue\"/>&nbsp;";
$sHTMLValue .= "<a class=\"no-arrow\" href=\"javascript:oACWidget_{$this->iId}.Search();\"><img style=\"border:0;vertical-align:middle;\" src=\"../images/mini_search.gif\" /></a>&nbsp;";
if ($bCreate)
{
$sHTMLValue .= "<a class=\"no-arrow\" href=\"javascript:oACWidget_{$this->iId}.CreateObject();\"><img style=\"border:0;vertical-align:middle;\" src=\"../images/mini_add.gif\" /></a>&nbsp;";
}
$sHTMLValue .= "<span id=\"v_{$this->iId}\"></span>";
// another hidden input to store & pass the object's Id
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"attr_{$this->sFieldPrefix}{$this->sAttCode}{$this->sNameSuffix}\" value=\"$this->value\" />\n";
@@ -120,7 +129,12 @@ EOF
$oPage->add_ready_script("\$('#label_$this->iId').blur(function() { $(this).search(); } );");
$oPage->add_ready_script("\$('#label_$this->iId').result( function(event, data, formatted) { OnAutoComplete('$this->iId', event, data, formatted); } );");
$oPage->add_ready_script("\$('#ac_dlg_$this->iId').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$this->sTitle', resizeStop: oACWidget_{$this->iId}.UpdateSizes, close: oACWidget_{$this->iId}.OnClose });\n");
$oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$this->sTitle'});\n");
$oPage->add_at_the_end($this->GetSearchDialog($oPage)); // To prevent adding forms inside the main form
if ($bCreate)
{
$oPage->add_at_the_end($this->GetCreationDialog($oPage)); // To prevent adding forms inside the main form
}
return $sHTMLValue;
}
@@ -143,12 +157,29 @@ EOF
$sHTML .= "</form>\n";
$sHTML .= '</div></div></div>';
$oPage->add_ready_script("$('#fs_{$this->iId}').bind('submit.uilinksWizard', oACWidget_{$this->iId}.DoSearchObjects);");
$oPage->add_ready_script("$('#fs_{$this->iId}').bind('submit.uiAutocomplete', oACWidget_{$this->iId}.DoSearchObjects);");
$oPage->add_ready_script("$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);");
return $sHTML;
}
protected function GetCreationDialog(WebPage $oPage)
{
$sHTML = '<div id="ac_create_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div id="dcr_'.$this->iId.'">';
//$sHTML .= "<form id=\"fcr_{$this->iId}\" OnSubmit=\"return oACWidget_{$this->iId}.DoCreate();\">\n";
//cmdbAbstractObject::DisplayCreationForm($oPage, 'Person', null, array());
//$sHTML .= "<input type=\"button\" id=\"btn_create_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ac_create_{$this->iId}').dialog('close');\">&nbsp;&nbsp;";
//$sHTML .= "<input type=\"button\" id=\"btn_create_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:New')."\" onClick=\"oACWidget_{$this->iId}.DoCreate();\">";
//$sHTML .= "</form>\n";
$sHTML .= '</div></div></div>';
//$oPage->add_ready_script("$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);");
return $sHTML;
}
/**
* Search for objects to be selected
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
@@ -181,5 +212,42 @@ EOF
$oObj = MetaModel::GetObject($this->sTargetClass, $iObjId);
return $oObj->GetName();
}
/**
* Get the form to create a new object of the 'target' class
*/
public function GetObjectCreationForm(WebPage $oPage)
{
$oPage->add("<h1>".MetaModel::GetClassIcon($this->sTargetClass)."&nbsp;".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sTargetClass))."</h1>\n");
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, null, array(), array('formPrefix' => $this->iId, 'noRelations' => true));
$oPage->add_ready_script("$('#dcr_{$this->iId} form').removeAttr('onsubmit');");
$oPage->add_ready_script("$('#dcr_{$this->iId} form').bind('submit.uilinksWizard', oACWidget_{$this->iId}.DoCreateObject);");
}
/**
* Get the form to create a new object of the 'target' class
*/
public function DoCreateObject($oPage)
{
$oObj = MetaModel::NewObject($this->sTargetClass);
$oObj->UpdateObject($this->sFormPrefix.$this->iId);
$oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
if (UserRights::IsImpersonated())
{
$sUserString = Dict::Format('UI:Archive_User_OnBehalfOf_User', UserRights::GetRealUser(), UserRights::GetUser());
}
else
{
$sUserString = UserRights::GetUser();
}
$oMyChange->Set("userinfo", $sUserString);
$iChangeId = $oMyChange->DBInsert();
$oObj->DBInsertTracked($oMyChange);
return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey());
//return array('name' => 'test', 'id' => '42');
}
}
?>

View File

@@ -227,6 +227,11 @@ class WizardHelper
return $this->m_aData['m_sClass'];
}
public function GetFormPrefix()
{
return $this->m_aData['m_sFormPrefix'];
}
public function GetIdForField($sFieldName)
{
$sResult = '';

BIN
images/mini_add.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

View File

@@ -13,7 +13,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
function AutocompleteWidget(id, sClass, sAttCode, sSuffix)
function AutocompleteWidget(id, sClass, sAttCode, sSuffix, oWizHelper)
{
this.id = id;
this.sClass = sClass;
@@ -21,7 +21,10 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix)
this.sSuffix = sSuffix;
this.emptyHtml = ''; // content to be displayed when the search results are empty (when opening the dialog)
this.emptyOnClose = true; // Workaround for the JQuery dialog being very slow when opening and closing if the content contains many INPUT tags
this.oWizardHelper = oWizHelper;
this.ajax_request = null;
var me = this;
this.Init = function()
{
// make sure that the form is clean
@@ -30,6 +33,15 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix)
$('#'+this.id+'_linksToRemove').val('');
}
this.StopPendingRequest = function()
{
if (this.ajax_request)
{
this.ajax_request.Abort();
this.ajax_request = null;
}
}
this.Search = function()
{
$('#ac_dlg_'+me.id).dialog('open');
@@ -66,8 +78,6 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix)
}
}
var ajax_request = null;
this.DoSearchObjects = function(id)
{
var theMap = { sAttCode: me.sAttCode,
@@ -86,8 +96,8 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix)
}
);
oWizardHelper.UpdateWizard();
theMap['json'] = oWizardHelper.ToJSON();
me.oWizardHelper.UpdateWizard();
theMap['json'] = me.oWizardHelper.ToJSON();
theMap['sRemoteClass'] = theMap['class']; // swap 'class' (defined in the form) and 'remoteClass'
theMap['class'] = me.sClass;
@@ -100,14 +110,10 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix)
// Make sure that we cancel any pending request before issuing another
// since responses may arrive in arbitrary order
if (ajax_request != null)
{
ajax_request.abort();
ajax_request = null;
}
this.StopPendingRequest();
// Run the query and display the results
ajax_request = $.post( 'ajax.render.php', theMap,
this.ajax_request = $.post( 'ajax.render.php', theMap,
function(data)
{
$(sSearchAreaId).html(data);
@@ -115,7 +121,7 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix)
$(sSearchAreaId+' .listResults').tablesorter( { headers: {0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
$('#fr_'+me.id+' input:radio').click(function() { me.UpdateButtons(); });
me.UpdateButtons();
ajax_request = null;
me.ajax_request = null;
},
'html'
);
@@ -140,21 +146,18 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix)
// Make sure that we cancel any pending request before issuing another
// since responses may arrive in arbitrary order
if (ajax_request != null)
{
ajax_request.abort();
ajax_request = null;
}
this.StopPendingRequest();
// Run the query and get the result back directly in JSON
ajax_request = $.post( 'ajax.render.php', theMap,
this.ajax_request = $.post( 'ajax.render.php', theMap,
function(data)
{
$('#label_'+me.id).val(data.name);
$('#label_'+me.id).removeClass('ac_loading');
$('#'+me.id).val(iObjectId);
$('#'+me.id).trigger('validate');
ajax_request = null;
$('#label_'+me.id).focus();
me.ajax_request = null;
},
'json'
);
@@ -174,4 +177,96 @@ function AutocompleteWidget(id, sClass, sAttCode, sSuffix)
}
$('#label_'+me.id).focus();
}
this.CreateObject = function(oWizHelper)
{
// Query the server to get the form to create a target object
$('#label_'+me.id).addClass('ac_loading');
me.oWizardHelper.UpdateWizard();
var theMap = { sAttCode: me.sAttCode,
iInputId: me.id,
sSuffix: me.sSuffix,
'class': me.sClass,
'json': me.oWizardHelper.ToJSON(),
operation: 'objectCreationForm'
}
// Make sure that we cancel any pending request before issuing another
// since responses may arrive in arbitrary order
this.StopPendingRequest();
// Run the query and get the result back directly in JSON
this.ajax_request = $.post( 'ajax.render.php', theMap,
function(data)
{
$('#dcr_'+me.id).html(data);
// Adjust the height of the dialog
$('#ac_create_'+me.id).dialog('open');
var h = $('#ac_create_'+me.id+' .wizContainer').outerHeight();
$('#ac_create_'+me.id).dialog( "option", "height", h+55 ); // space for dialog title and padding...
$('#ac_create_'+me.id).dialog( "option", "close", function() { $('#label_'+me.id).removeClass('ac_loading'); $('#label_'+me.id).focus(); } );
// Modify the action of the cancel button
$('#ac_create_'+me.id+' button.cancel').unbind('click').click( me.CloseCreateObject );
me.ajax_request = null;
},
'html'
);
}
this.CloseCreateObject = function()
{
$('#ac_create_'+me.id).dialog( "close" );
$('#dcr_'+me.id).html('');
}
this.DoCreateObject = function()
{
var sFormId = $('#dcr_'+me.id+' form').attr('id');
if (CheckFields(sFormId, true))
{
$('#'+sFormId).block();
var theMap = { sAttCode: me.sAttCode,
iInputId: me.id,
sSuffix: me.sSuffix,
'class': me.sClass,
'json': me.oWizardHelper.ToJSON()
}
// Gather the values from the form
// Gather the parameters from the search form
$('#'+sFormId+' :input').each(
function(i)
{
if (this.name != '')
{
theMap[this.name] = this.value;
}
}
);
// Override the 'operation' code
theMap['operation'] = 'doCreateObject';
theMap['class'] = me.sClass;
$('#ac_create_'+me.id).dialog('close');
// Make sure that we cancel any pending request before issuing another
// since responses may arrive in arbitrary order
this.StopPendingRequest();
// Run the query and get the result back directly in JSON
this.ajax_request = $.post( 'ajax.render.php', theMap,
function(data)
{
$('#label_'+me.id).val(data.name);
$('#'+me.id).val(data.id);
$('#'+me.id).trigger('validate');
$('#label_'+me.id).removeClass('ac_loading');
$('#label_'+me.id).focus();
me.ajax_request = null;
},
'json'
);
}
return false; // do NOT submit the form
}
}

View File

@@ -231,6 +231,7 @@ function ValidateCKEditField(sFieldId, sPattern, bMandatory, sFormId, nullValue)
setTimeout(function(){ValidateCKEditField(sFieldId, sPattern, bMandatory, sFormId, nullValue);}, 500);
}
/*
function UpdateDependentFields(aFieldNames)
{
//console.log('UpdateDependentFields:');
@@ -248,6 +249,7 @@ function UpdateDependentFields(aFieldNames)
}
oWizardHelper.AjaxQueryServer();
}
*/
function ResetPwd(id)
{

View File

@@ -1,5 +1,5 @@
// Wizard Helper JavaScript class to communicate with the WizardHelper PHP class
function WizardHelper(sClass)
function WizardHelper(sClass, sFormPrefix)
{
this.m_oData = { 'm_sClass' : '',
'm_oFieldsMap': {},
@@ -8,7 +8,8 @@ function WizardHelper(sClass)
'm_aAllowedValuesRequested': [],
'm_oDefaultValue': {},
'm_oAllowedValues': {},
'm_iFieldsCount' : 0
'm_iFieldsCount' : 0,
'm_sFormPrefix' : sFormPrefix
};
this.m_oData.m_sClass = sClass;
@@ -135,4 +136,20 @@ function WizardHelper(sClass)
this.m_oData.m_oCurrentValues[sFieldCode] = value;
return value;
}
this.UpdateDependentFields = function(aFieldNames)
{
index = 0;
this.ResetQuery();
this.UpdateWizard();
while(index < aFieldNames.length )
{
sAttCode = aFieldNames[index];
sFieldId = this.GetFieldId(sAttCode);
$('#v_'+sFieldId).html('<img src="../images/indicator.gif" />');
this.RequestAllowedValues(sAttCode);
index++;
}
this.AjaxQueryServer();
}
}

View File

@@ -75,7 +75,6 @@ switch($operation)
$sAttCode = utils::ReadParam('sAttCode', '');
$iInputId = utils::ReadParam('iInputId', '');
$sSuffix = utils::ReadParam('sSuffix', '');
// To do: retrieve the object under construction & use it to filter the allowed values
$sJson = utils::ReadParam('json', '');
$oWizardHelper = WizardHelper::FromJSON($sJson);
$oObj = $oWizardHelper->GetTargetObject();
@@ -84,6 +83,36 @@ switch($operation)
$oWidget->SearchObjectsToSelect($oPage, $sTargetClass);
break;
// ui.autocompletewidget
case 'objectCreationForm':
$sTargetClass = utils::ReadParam('sRemoteClass', '');
$sAttCode = utils::ReadParam('sAttCode', '');
$iInputId = utils::ReadParam('iInputId', '');
$sSuffix = utils::ReadParam('sSuffix', '');
$sJson = utils::ReadParam('json', '');
$oWizardHelper = WizardHelper::FromJSON($sJson);
$oObj = $oWizardHelper->GetTargetObject();
$aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, array('this' => $oObj));
$oWidget = new UIAutocompleteWidget($sAttCode, $sClass, '', $aAllowedValues, $oObj->Get($sAttCode), $iInputId, $sSuffix, '');
$oWidget->GetObjectCreationForm($oPage);
break;
// ui.autocompletewidget
case 'doCreateObject':
$sTargetClass = utils::ReadParam('sRemoteClass', '');
$sAttCode = utils::ReadParam('sAttCode', '');
$iInputId = utils::ReadParam('iInputId', '');
$sSuffix = utils::ReadParam('sSuffix', '');
$sJson = utils::ReadParam('json', '');
$oWizardHelper = WizardHelper::FromJSON($sJson);
$oObj = $oWizardHelper->GetTargetObject();
$aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, array('this' => $oObj));
// The iInputId of the autocomplete is the prefix for the form used to create the target object
$oWidget = new UIAutocompleteWidget($sAttCode, $sClass, '', $aAllowedValues, null, $iInputId, $sSuffix, $oWizardHelper->GetFormPrefix());
$aResult = $oWidget->DoCreateObject($oPage);
echo json_encode($aResult);
break;
// ui.autocompletewidget
case 'getObjectName':
$sTargetClass = utils::ReadParam('sTargetClass', '');
@@ -126,6 +155,7 @@ switch($operation)
$oWizardHelper->SetDefaultValue($sAttCode, $defaultValue);
$oObj->Set($sAttCode, $defaultValue);
}
$sFormPrefix = $oWizardHelper->GetFormPrefix();
foreach($oWizardHelper->GetFieldsForAllowedValues() as $sAttCode)
{
$sId = $oWizardHelper->GetIdForField($sAttCode);
@@ -138,13 +168,13 @@ switch($operation)
$displayValue = $oObj->GetEditValue($sAttCode);
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$iFlags = MetaModel::GetAttributeFlags($sClass, $oObj->GetState(), $sAttCode);
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $value, $displayValue, $sId, '', $iFlags, array('this' => $oObj));
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $value, $displayValue, $sId, '', $iFlags, array('this' => $oObj, 'formPrefix' => $sFormPrefix));
// Make sure that we immediatly validate the field when we reload it
$oPage->add_ready_script("$('#$sId').trigger('validate');");
$oWizardHelper->SetAllowedValuesHtml($sAttCode, $sHTMLValue);
}
}
$oPage->add("<script type=\"text/javascript\">\noWizardHelper.m_oData=".$oWizardHelper->ToJSON().";\noWizardHelper.UpdateFields();\n</script>\n");
$oPage->add_script("oWizardHelper{$sFormPrefix}.m_oData=".$oWizardHelper->ToJSON().";\noWizardHelper{$sFormPrefix}.UpdateFields();\n");
break;
case 'ajax':