(input)-------+ +-----------+ * | | | Browse... | * +-----------------------------+ +-----------+ * * And the popup dialog has the following layout: * * +------------------- ac_dlg_ (div)-----------+ * + +--- ds_ (div)---------------------------+ | * | | +------------- fs_ (form)------------+ | | * | | | +--------+---+ | | | * | | | | Class | V | | | | * | | | +--------+---+ | | | * | | | | | | * | | | S e a r c h F o r m | | | * | | | +--------+ | | | * | | | | Search | | | | * | | | +--------+ | | | * | | +----------------------------------------+ | | * | +--------------+-dh_-+--------------------+ | * | \ Search / | * | +------+ | * | +--- fr_ (form)--------------------------+ | * | | +------------ dr_ (div)--------------+ | | * | | | | | | * | | | S e a r c h R e s u l t s | | | * | | | | | | * | | +----------------------------------------+ | | * | | +--------+ +-----+ | | * | | | Cancel | | Add | | | * | | +--------+ +-----+ | | * | +--------------------------------------------+ | * +------------------------------------------------+ * @author Erwan Taloc * @author Romain Quetiez * @author Denis Flaven * @license http://www.opensource.org/licenses/gpl-3.0.html LGPL */ require_once(APPROOT.'/application/webpage.class.inc.php'); require_once(APPROOT.'/application/displayblock.class.inc.php'); class UIExtKeyWidget { protected static $iWidgetIndex = 0; protected $sAttCode; protected $sNameSuffix; protected $iId; protected $sTitle; public function __construct($sAttCode, $sClass, $sTitle, $aAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '') { self::$iWidgetIndex++; $this->sAttCode = $sAttCode; $this->sClass = $sClass; $this->oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $this->sNameSuffix = $sNameSuffix; $this->iId = $iInputId; $this->aAllowedValues = $aAllowedValues; $this->value = $value; $this->sFieldPrefix = $sFieldPrefix; $this->sTargetClass = $this->oAttDef->GetTargetClass(); $this->sTitle = $sTitle; $this->sFormPrefix = $sFormPrefix; $this->bMandatory = $bMandatory; } /** * Get the HTML fragment corresponding to the linkset editing widget * @param WebPage $oP The web page used for all the output * @param Hash $aArgs Extra context arguments * @return string The HTML fragment to be inserted into the page */ public function Display(WebPage $oPage, $aArgs = array(), $bSearchMode = false) { $oPage->add_linked_script('../js/extkeywidget.js'); $oPage->add_linked_script('../js/forms-json-utils.js'); $bCreate = (!$bSearchMode) && (!MetaModel::IsAbstract($this->sTargetClass)) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $this->oAttDef->AllowTargetCreation()); $sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm'); $sAttrFieldPrefix = ($bSearchMode) ? '' : 'attr_'; $sHTMLValue = ""; // no wrap if($bSearchMode) { $sWizHelper = 'null'; } else { $sWizHelper = 'oWizardHelper'.$this->sFormPrefix; } if (count($this->aAllowedValues) < $this->oAttDef->GetMaximumComboLength()) { // Few choices, use a normal 'select' $sSelectMode = 'true'; $sHelpText = $this->oAttDef->GetHelpOnEdition(); // In case there are no valid values, the select will be empty, thus blocking the user from validating the form $sHTMLValue = "\n"; $oPage->add_ready_script( <<iId} = new ExtKeyWidget('{$this->iId}', '{$this->sClass}', '{$this->sAttCode}', '{$this->sNameSuffix}', $sSelectMode, $sWizHelper); oACWidget_{$this->iId}.emptyHtml = "

$sMessage

"; EOF ); } else { // Too many choices, use an autocomplete $sSelectMode = 'false'; if ($this->oAttDef->IsNull($this->value)) // Null values are displayed as '' { $sDisplayValue = ''; } else { $sDisplayValue = $this->GetObjectName($this->value); } $sFormPrefix = $this->sFormPrefix; $iMinChars = $this->oAttDef->GetMinAutoCompleteChars(); $iFieldSize = $this->oAttDef->GetMaxSize(); // the input for the auto-complete $sHTMLValue = "aAllowedValues)."\" type=\"text\" id=\"label_$this->iId\" size=\"30\" maxlength=\"$iFieldSize\" value=\"$sDisplayValue\"/> "; $sHTMLValue .= "iId}.Search();\"> "; // another hidden input to store & pass the object's Id $sHTMLValue .= "iId\" name=\"{$sAttrFieldPrefix}{$this->sFieldPrefix}{$this->sAttCode}{$this->sNameSuffix}\" value=\"$this->value\" />\n"; // Scripts to start the autocomplete and bind some events to it $oPage->add_ready_script( <<iId} = new ExtKeyWidget('{$this->iId}', '{$this->sClass}', '{$this->sAttCode}', '{$this->sNameSuffix}', $sSelectMode, $sWizHelper); oACWidget_{$this->iId}.emptyHtml = "

$sMessage

"; $('#label_$this->iId').autocomplete('./ajax.render.php', { scroll:true, minChars:{$iMinChars}, formatItem:formatItem, autoFill:false, matchContains:true, keyHolder:'#{$this->iId}', extraParams:{operation:'autocomplete', sclass:'{$this->sClass}',attCode:'{$this->sAttCode}'}}); $('#label_$this->iId').blur(function() { $(this).search(); } ); $('#label_$this->iId').result( function(event, data, formatted) { OnAutoComplete('{$this->iId}', event, data, formatted); } ); $('#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 }); EOF ); $oPage->add_at_the_end($this->GetSearchDialog($oPage)); // To prevent adding forms inside the main form } if ($bCreate) { $sHTMLValue .= "iId}.CreateObject();\"> "; $oPage->add_at_the_end('
'); } $sHTMLValue .= "iId}\">"; $sHTMLValue .= "
"; // end of no wrap return $sHTMLValue; } protected function GetSearchDialog(WebPage $oPage) { $sHTML = '
'; $oFilter = new DBObjectSearch($this->sTargetClass); $oSet = new CMDBObjectSet($oFilter); $oBlock = new DisplayBlock($oFilter, 'search', false); $sHTML .= $oBlock->GetDisplay($oPage, $this->iId, array('open' => true, 'currentId' => $this->iId)); $sHTML .= "
iId}\" OnSubmit=\"return oACWidget_{$this->iId}.DoOk();\">\n"; $sHTML .= "
iId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n"; $sHTML .= "

".Dict::S('UI:Message:EmptyList:UseSearchForm')."

\n"; $sHTML .= "
\n"; $sHTML .= "iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ac_dlg_{$this->iId}').dialog('close');\">  "; $sHTML .= "iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoOk();\">"; $sHTML .= "
\n"; $sHTML .= '
'; $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; } /** * Search for objects to be selected * @param WebPage $oP The page used for the output (usually an AjaxWebPage) * @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass * @param Array $aAlreadyLinkedIds List of IDs of objects of "remote" class already linked, to be filtered out of the search */ public function SearchObjectsToSelect(WebPage $oP, $sTargetClass = '') { if ($sTargetClass != '') { // assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass)); $oFilter = new DBObjectSearch($sTargetClass); } else { // No remote class specified use the one defined in the linkedset $oFilter = new DBObjectSearch($this->sTargetClass); } $oFilter->AddCondition('id', array_keys($this->aAllowedValues), 'IN'); $oSet = new CMDBObjectSet($oFilter); $oBlock = new DisplayBlock($oFilter, 'list', false); $oBlock->Display($oP, $this->iId, array('menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'display_limit' => false)); // Don't display the 'Actions' menu on the results } /** * Get the display name of the selected object, to fill back the autocomplete */ public function GetObjectName($iObjId) { $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('
'); $oPage->add("

".MetaModel::GetClassIcon($this->sTargetClass)." ".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sTargetClass))."

\n"); cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, null, array(), array('formPrefix' => $this->iId, 'noRelations' => true)); $oPage->add('
'); $oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: $(window).width()*0.8, height: 'auto', autoOpen: false, modal: true, title: '$this->sTitle'});\n"); $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()); $sUserString = CMDBChange::GetCurrentUserName(); $oMyChange->Set("userinfo", $sUserString); $iChangeId = $oMyChange->DBInsert(); $oObj->DBInsertTracked($oMyChange); return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey()); //return array('name' => 'test', 'id' => '42'); } } ?>