mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
Improved implementation of the 'autocomplete' input and fix of quite a few related issue with aysnchronous inputs. Autocompletes are now restricted to external keys only.
Some details:
- Autocomplete now matches on 'contains' instead of 'begins with'
- The minimum size of this match is configurable in the config file and per attribute ('min_autocomplete_chars').
- The maximum size that turns a drop-down list into an autocomplete is configurable in the config-file and per attribute ('max_combo_length').
- Better feedback when expanding/collapsing search results lists.
- 'Pointer' cursor on the link to Expand/Collapse results lists.
- The 'mandatory' state of an attribute is no longer lost when some part of a form is reloaded asynchronously
SVN:trunk[947]
This commit is contained in:
@@ -60,6 +60,7 @@ class ajax_page extends WebPage
|
|||||||
$s_captured_output = ob_get_contents();
|
$s_captured_output = ob_get_contents();
|
||||||
ob_end_clean();
|
ob_end_clean();
|
||||||
echo $this->s_content;
|
echo $this->s_content;
|
||||||
|
echo $this->s_deferred_content;
|
||||||
if (!empty($this->m_sReadyScript))
|
if (!empty($this->m_sReadyScript))
|
||||||
{
|
{
|
||||||
echo "<script>\n";
|
echo "<script>\n";
|
||||||
@@ -94,6 +95,17 @@ class ajax_page extends WebPage
|
|||||||
// considering that at this time everything in the page is "ready"...
|
// considering that at this time everything in the page is "ready"...
|
||||||
$this->m_sReadyScript .= $sScript;
|
$this->m_sReadyScript .= $sScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cannot be called in this context, since Ajax pages do not share
|
||||||
|
* any context with the calling page !!
|
||||||
|
*/
|
||||||
|
public function GetUniqueId()
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ require_once('../application/utils.inc.php');
|
|||||||
require_once('../application/applicationcontext.class.inc.php');
|
require_once('../application/applicationcontext.class.inc.php');
|
||||||
require_once('../application/ui.linkswidget.class.inc.php');
|
require_once('../application/ui.linkswidget.class.inc.php');
|
||||||
require_once('../application/ui.passwordwidget.class.inc.php');
|
require_once('../application/ui.passwordwidget.class.inc.php');
|
||||||
|
require_once('../application/ui.autocompletewidget.class.inc.php');
|
||||||
require_once('../application/ui.htmleditorwidget.class.inc.php');
|
require_once('../application/ui.htmleditorwidget.class.inc.php');
|
||||||
|
|
||||||
abstract class cmdbAbstractObject extends CMDBObject
|
abstract class cmdbAbstractObject extends CMDBObject
|
||||||
@@ -385,8 +386,14 @@ abstract class cmdbAbstractObject extends CMDBObject
|
|||||||
*/
|
*/
|
||||||
public static function GetDisplaySet(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
|
public static function GetDisplaySet(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
|
||||||
{
|
{
|
||||||
static $iListId = 0;
|
if (empty($aExtraParams['currentId']))
|
||||||
$iListId++;
|
{
|
||||||
|
$iListId = $oPage->GetUniqueId(); // Works only if not in an Ajax page !!
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$iListId = $aExtraParams['currentId'];
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize and check the parameters
|
// Initialize and check the parameters
|
||||||
$bViewLink = isset($aExtraParams['view_link']) ? $aExtraParams['view_link'] : true;
|
$bViewLink = isset($aExtraParams['view_link']) ? $aExtraParams['view_link'] : true;
|
||||||
@@ -526,14 +533,14 @@ abstract class cmdbAbstractObject extends CMDBObject
|
|||||||
}
|
}
|
||||||
$sHtml .= '<table class="listContainer">';
|
$sHtml .= '<table class="listContainer">';
|
||||||
$sColspan = '';
|
$sColspan = '';
|
||||||
if (isset($aExtraParams['block_id']))
|
// if (isset($aExtraParams['block_id']))
|
||||||
{
|
// {
|
||||||
$divId = $aExtraParams['block_id'];
|
// $divId = $aExtraParams['block_id'];
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
$divId = 'missingblockid';
|
// $divId = 'missingblockid';
|
||||||
}
|
// }
|
||||||
$sFilter = $oSet->GetFilter()->serialize();
|
$sFilter = $oSet->GetFilter()->serialize();
|
||||||
$iMinDisplayLimit = utils::GetConfig()->GetMinDisplayLimit();
|
$iMinDisplayLimit = utils::GetConfig()->GetMinDisplayLimit();
|
||||||
$sCollapsedLabel = Dict::Format('UI:TruncatedResults', $iMinDisplayLimit, $oSet->Count());
|
$sCollapsedLabel = Dict::Format('UI:TruncatedResults', $iMinDisplayLimit, $oSet->Count());
|
||||||
@@ -546,11 +553,11 @@ abstract class cmdbAbstractObject extends CMDBObject
|
|||||||
{
|
{
|
||||||
// list truncated
|
// list truncated
|
||||||
$aExtraParams['display_limit'] = true;
|
$aExtraParams['display_limit'] = true;
|
||||||
$sHtml .= '<tr class="containerHeader"><td><span id="lbl_'.$divId.'">'.$sCollapsedLabel.'</span> <a class="truncated" id="trc_'.$divId.'">'.$sLinkLabel.'</a></td><td>';
|
$sHtml .= '<tr class="containerHeader"><td><span id="lbl_'.$iListId.'">'.$sCollapsedLabel.'</span> <a class="truncated" id="trc_'.$iListId.'">'.$sLinkLabel.'</a></td><td>';
|
||||||
$oPage->add_ready_script(
|
$oPage->add_ready_script(
|
||||||
<<<EOF
|
<<<EOF
|
||||||
$('#$divId table.listResults').addClass('truncated');
|
$('#$iListId table.listResults').addClass('truncated');
|
||||||
$('#$divId table.listResults tr:last td').addClass('truncated');
|
$('#$iListId table.listResults tr:last td').addClass('truncated');
|
||||||
EOF
|
EOF
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -558,14 +565,14 @@ EOF
|
|||||||
{
|
{
|
||||||
// Collapsible list
|
// Collapsible list
|
||||||
$aExtraParams['display_limit'] = true;
|
$aExtraParams['display_limit'] = true;
|
||||||
$sHtml .= '<tr class="containerHeader"><td><span id="lbl_'.$divId.'">'.Dict::Format('UI:CountOfResults', $oSet->Count()).'</span><a class="truncated" id="trc_'.$divId.'">'.Dict::S('UI:CollapseList').'</a></td><td>';
|
$sHtml .= '<tr class="containerHeader"><td><span id="lbl_'.$iListId.'">'.Dict::Format('UI:CountOfResults', $oSet->Count()).'</span><a class="truncated" id="trc_'.$iListId.'">'.Dict::S('UI:CollapseList').'</a></td><td>';
|
||||||
}
|
}
|
||||||
$aExtraParams['truncated'] = false; // To expand the full list when clicked
|
$aExtraParams['truncated'] = false; // To expand the full list when clicked
|
||||||
$sExtraParamsExpand = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
|
$sExtraParamsExpand = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
|
||||||
$oPage->add_ready_script(
|
$oPage->add_ready_script(
|
||||||
<<<EOF
|
<<<EOF
|
||||||
// Handle truncated lists
|
// Handle truncated lists
|
||||||
$('#trc_$divId').click(function()
|
$('#trc_$iListId').click(function()
|
||||||
{
|
{
|
||||||
var state = {};
|
var state = {};
|
||||||
|
|
||||||
@@ -582,15 +589,15 @@ EOF
|
|||||||
$.bbq.pushState( state );
|
$.bbq.pushState( state );
|
||||||
$(this).trigger(state[this.id]);
|
$(this).trigger(state[this.id]);
|
||||||
});
|
});
|
||||||
|
$('#trc_$iListId').unbind('open');
|
||||||
$('#trc_$divId').bind('open', function()
|
$('#trc_$iListId').bind('open', function()
|
||||||
{
|
{
|
||||||
ReloadTruncatedList('$divId', '$sFilter', '$sExtraParamsExpand');
|
ReloadTruncatedList('$iListId', '$sFilter', '$sExtraParamsExpand');
|
||||||
});
|
});
|
||||||
|
$('#trc_$iListId').unbind('close');
|
||||||
$('#trc_$divId').bind('close', function()
|
$('#trc_$iListId').bind('close', function()
|
||||||
{
|
{
|
||||||
TruncateList('$divId', $iMinDisplayLimit, '$sCollapsedLabel', '$sLinkLabel');
|
TruncateList('$iListId', $iMinDisplayLimit, '$sCollapsedLabel', '$sLinkLabel');
|
||||||
});
|
});
|
||||||
EOF
|
EOF
|
||||||
);
|
);
|
||||||
@@ -604,7 +611,7 @@ EOF
|
|||||||
//$aMenuExtraParams['linkage'] = $sLinkageAttribute;
|
//$aMenuExtraParams['linkage'] = $sLinkageAttribute;
|
||||||
$aMenuExtraParams = $aExtraParams;
|
$aMenuExtraParams = $aExtraParams;
|
||||||
}
|
}
|
||||||
$sHtml .= $oMenuBlock->GetRenderContent($oPage, $aMenuExtraParams);
|
$sHtml .= $oMenuBlock->GetRenderContent($oPage, $aMenuExtraParams, $iListId);
|
||||||
$sHtml .= '</td></tr>';
|
$sHtml .= '</td></tr>';
|
||||||
}
|
}
|
||||||
$sHtml .= "<tr><td $sColspan>";
|
$sHtml .= "<tr><td $sColspan>";
|
||||||
@@ -872,13 +879,12 @@ EOF
|
|||||||
if (isset($aExtraParams['currentId']))
|
if (isset($aExtraParams['currentId']))
|
||||||
{
|
{
|
||||||
$sSearchFormId = $aExtraParams['currentId'];
|
$sSearchFormId = $aExtraParams['currentId'];
|
||||||
$iSearchFormId++;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$iSearchFormId++;
|
$iSearchFormId = $oPage->GetUniqueId();
|
||||||
$sSearchFormId = 'SimpleSearchForm'.$iSearchFormId;
|
$sSearchFormId = 'SimpleSearchForm'.$iSearchFormId;
|
||||||
$sHtml .= "<div id=\"$sSearchFormId\" class=\"mini_tab{$iSearchFormId}\">\n";
|
$sHtml .= "<div id=\"ds_$sSearchFormId\" class=\"mini_tab{$iSearchFormId}\">\n";
|
||||||
}
|
}
|
||||||
// Check if the current class has some sub-classes
|
// Check if the current class has some sub-classes
|
||||||
if (isset($aExtraParams['baseClass']))
|
if (isset($aExtraParams['baseClass']))
|
||||||
@@ -908,7 +914,7 @@ EOF
|
|||||||
$sClassesCombo = MetaModel::GetName($sClassName);
|
$sClassesCombo = MetaModel::GetName($sClassName);
|
||||||
}
|
}
|
||||||
$oUnlimitedFilter = new DBObjectSearch($sClassName);
|
$oUnlimitedFilter = new DBObjectSearch($sClassName);
|
||||||
$sHtml .= "<form id=\"form{$iSearchFormId}\" action=\"../pages/UI.php\">\n"; // Don't use $_SERVER['SCRIPT_NAME'] since the form may be called asynchronously (from ajax.php)
|
$sHtml .= "<form id=\"fs_{$sSearchFormId}\" action=\"../pages/UI.php\">\n"; // Don't use $_SERVER['SCRIPT_NAME'] since the form may be called asynchronously (from ajax.php)
|
||||||
$sHtml .= "<h2>".Dict::Format('UI:SearchFor_Class_Objects', $sClassesCombo)."</h2>\n";
|
$sHtml .= "<h2>".Dict::Format('UI:SearchFor_Class_Objects', $sClassesCombo)."</h2>\n";
|
||||||
$index = 0;
|
$index = 0;
|
||||||
$sHtml .= "<p>\n";
|
$sHtml .= "<p>\n";
|
||||||
@@ -1042,7 +1048,7 @@ EOF
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$iInputId++;
|
$oPoage->GetUniqueId();
|
||||||
$iId = $iInputId;
|
$iId = $iInputId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1120,6 +1126,44 @@ EOF
|
|||||||
// Event list & validation is handled directly by the widget
|
// Event list & validation is handled directly by the widget
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'ExtKey':
|
||||||
|
$aEventsList[] ='validate';
|
||||||
|
$aEventsList[] ='change';
|
||||||
|
|
||||||
|
// #@# todo - add context information (depending on dimensions)
|
||||||
|
$aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, $aArgs);
|
||||||
|
$iFieldSize = $oAttDef->GetMaxSize();
|
||||||
|
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
|
||||||
|
if (count($aAllowedValues) >= $iMaxComboLength)
|
||||||
|
{
|
||||||
|
// too many choices, use an autocomplete
|
||||||
|
$oWidget = new UIAutoCompleteWidget($sAttCode, $sClass, $oAttDef->GetLabel(), $aAllowedValues, $value, $iId, $sNameSuffix, $sFieldPrefix);
|
||||||
|
$sHTMLValue = $oWidget->Display($oPage, $aArgs);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Few choices, use a normal 'select'
|
||||||
|
// In case there are no valid values, the select will be empty, thus blocking the user from validating the form
|
||||||
|
$sHTMLValue = "<select title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" id=\"$iId\">\n";
|
||||||
|
$sHTMLValue .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>\n";
|
||||||
|
foreach($aAllowedValues as $key => $display_value)
|
||||||
|
{
|
||||||
|
if ((count($aAllowedValues) == 1) && ($sMandatory == 'true') )
|
||||||
|
{
|
||||||
|
// When there is only once choice, select it by default
|
||||||
|
$sSelected = ' selected';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$sSelected = ($value == $key) ? ' selected' : '';
|
||||||
|
}
|
||||||
|
$sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n";
|
||||||
|
}
|
||||||
|
$sHTMLValue .= "</select> {$sValidationField}\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'String':
|
case 'String':
|
||||||
default:
|
default:
|
||||||
$aEventsList[] ='validate';
|
$aEventsList[] ='validate';
|
||||||
@@ -1128,44 +1172,24 @@ EOF
|
|||||||
$iFieldSize = $oAttDef->GetMaxSize();
|
$iFieldSize = $oAttDef->GetMaxSize();
|
||||||
if ($aAllowedValues !== null)
|
if ($aAllowedValues !== null)
|
||||||
{
|
{
|
||||||
if (count($aAllowedValues) > 50)
|
// Discrete list of values, use a SELECT
|
||||||
|
$sHTMLValue = "<select title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" id=\"$iId\">\n";
|
||||||
|
$sHTMLValue .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>\n";
|
||||||
|
foreach($aAllowedValues as $key => $display_value)
|
||||||
{
|
{
|
||||||
// too many choices, use an autocomplete
|
if ((count($aAllowedValues) == 1) && ($sMandatory == 'true') )
|
||||||
// The input for the auto complete
|
|
||||||
if ($oAttDef->IsNull($value)) // Null values are displayed as ''
|
|
||||||
{
|
{
|
||||||
$sDisplayValue = '';
|
// When there is only once choice, select it by default
|
||||||
|
$sSelected = ' selected';
|
||||||
}
|
}
|
||||||
$sHTMLValue = "<input count=\"".count($aAllowedValues)."\" type=\"text\" id=\"label_$iId\" size=\"30\" maxlength=\"$iFieldSize\" value=\"$sDisplayValue\"/> {$sValidationField}";
|
else
|
||||||
// another hidden input to store & pass the object's Id
|
|
||||||
$sHTMLValue .= "<input type=\"hidden\" id=\"$iId\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"$value\" />\n";
|
|
||||||
$oPage->add_ready_script("\$('#label_$iId').autocomplete('./ajax.render.php', { scroll:true, minChars:3, formatItem:formatItem, autoFill:true, keyHolder:'#$iId', extraParams:{operation:'autocomplete', sclass:'$sClass',attCode:'".$sAttCode."'}});");
|
|
||||||
$oPage->add_ready_script("\$('#label_$iId').blur(function() { $(this).search(); } );");
|
|
||||||
$oPage->add_ready_script("\$('#label_$iId').result( function(event, data, formatted) { OnAutoComplete('$iId', event, data, formatted); } );");
|
|
||||||
$aEventsList[] ='change';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Few choices, use a normal 'select'
|
|
||||||
// In case there are no valid values, the select will be empty, thus blocking the user from validating the form
|
|
||||||
$sHTMLValue = "<select title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" id=\"$iId\">\n";
|
|
||||||
$sHTMLValue .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>\n";
|
|
||||||
foreach($aAllowedValues as $key => $display_value)
|
|
||||||
{
|
{
|
||||||
if ((count($aAllowedValues) == 1) && ($sMandatory == 'true') )
|
$sSelected = ($value == $key) ? ' selected' : '';
|
||||||
{
|
|
||||||
// When there is only once choice, select it by default
|
|
||||||
$sSelected = ' selected';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$sSelected = ($value == $key) ? ' selected' : '';
|
|
||||||
}
|
|
||||||
$sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n";
|
|
||||||
}
|
}
|
||||||
$sHTMLValue .= "</select> {$sValidationField}\n";
|
$sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n";
|
||||||
$aEventsList[] ='change';
|
|
||||||
}
|
}
|
||||||
|
$sHTMLValue .= "</select> {$sValidationField}\n";
|
||||||
|
$aEventsList[] ='change';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1173,7 +1197,7 @@ EOF
|
|||||||
$aEventsList[] ='keyup';
|
$aEventsList[] ='keyup';
|
||||||
$aEventsList[] ='change';
|
$aEventsList[] ='change';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$sPattern = addslashes($oAttDef->GetValidationPattern()); //'^([0-9]+)$';
|
$sPattern = addslashes($oAttDef->GetValidationPattern()); //'^([0-9]+)$';
|
||||||
if (!empty($aEventsList))
|
if (!empty($aEventsList))
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ class DisplayBlock
|
|||||||
{
|
{
|
||||||
$sHtml = '';
|
$sHtml = '';
|
||||||
$aExtraParams = array_merge($aExtraParams, $this->m_aParams);
|
$aExtraParams = array_merge($aExtraParams, $this->m_aParams);
|
||||||
$aExtraParams['block_id'] = $sId;
|
$aExtraParams['currentId'] = $sId;
|
||||||
$sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
|
$sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
|
||||||
|
|
||||||
$bAutoReload = false;
|
$bAutoReload = false;
|
||||||
@@ -253,7 +253,7 @@ class DisplayBlock
|
|||||||
{
|
{
|
||||||
// render now
|
// render now
|
||||||
$sHtml .= "<div id=\"$sId\" class=\"display_block\">\n";
|
$sHtml .= "<div id=\"$sId\" class=\"display_block\">\n";
|
||||||
$sHtml .= $this->GetRenderContent($oPage, $aExtraParams);
|
$sHtml .= $this->GetRenderContent($oPage, $aExtraParams, $sId);
|
||||||
$sHtml .= "</div>\n";
|
$sHtml .= "</div>\n";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -303,10 +303,18 @@ class DisplayBlock
|
|||||||
|
|
||||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||||
{
|
{
|
||||||
$oPage->add($this->GetRenderContent($oPage, $aExtraParams));
|
if (empty($aExtraParams['currentId']))
|
||||||
|
{
|
||||||
|
$sId = $oPage->GetUniqueId(); // Works only if the page is not an Ajax one !
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$sId = $aExtraParams['currentId'];
|
||||||
|
}
|
||||||
|
$oPage->add($this->GetRenderContent($oPage, $aExtraParams, $sId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetRenderContent(WebPage $oPage, $aExtraParams = array())
|
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
|
||||||
{
|
{
|
||||||
$sHtml = '';
|
$sHtml = '';
|
||||||
// Add the extra params into the filter if they make sense for such a filter
|
// Add the extra params into the filter if they make sense for such a filter
|
||||||
@@ -718,22 +726,21 @@ class DisplayBlock
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'search':
|
case 'search':
|
||||||
static $iSearchSectionId = 1;
|
|
||||||
$sStyle = (isset($aExtraParams['open']) && ($aExtraParams['open'] == 'true')) ? 'SearchDrawer' : 'SearchDrawer DrawerClosed';
|
$sStyle = (isset($aExtraParams['open']) && ($aExtraParams['open'] == 'true')) ? 'SearchDrawer' : 'SearchDrawer DrawerClosed';
|
||||||
$sHtml .= "<div id=\"Search_$iSearchSectionId\" class=\"$sStyle\">\n";
|
$sHtml .= "<div id=\"ds_$sId\" class=\"$sStyle\">\n";
|
||||||
$oPage->add_ready_script(
|
$oPage->add_ready_script(
|
||||||
<<<EOF
|
<<<EOF
|
||||||
$("#LnkSearch_$iSearchSectionId").click( function() {
|
$("#dh_$sId").click( function() {
|
||||||
$("#Search_$iSearchSectionId").slideToggle('normal', function() { $("#Search_$iSearchSectionId").parent().resize(); } );
|
$("#ds_$sId").slideToggle('normal', function() { $("#ds_$sId").parent().resize(); } );
|
||||||
$("#LnkSearch_$iSearchSectionId").toggleClass('open');
|
$("#dh_$sId").toggleClass('open');
|
||||||
});
|
});
|
||||||
EOF
|
EOF
|
||||||
);
|
);
|
||||||
|
$aExtraParams['currentId'] = $sId;
|
||||||
$sHtml .= cmdbAbstractObject::GetSearchForm($oPage, $this->m_oSet, $aExtraParams);
|
$sHtml .= cmdbAbstractObject::GetSearchForm($oPage, $this->m_oSet, $aExtraParams);
|
||||||
$sHtml .= "</div>\n";
|
$sHtml .= "</div>\n";
|
||||||
$sHtml .= "<div class=\"HRDrawer\"></div>\n";
|
$sHtml .= "<div class=\"HRDrawer\"></div>\n";
|
||||||
$sHtml .= "<div id=\"LnkSearch_$iSearchSectionId\" class=\"DrawerHandle\">".Dict::S('UI:SearchToggle')."</div>\n";
|
$sHtml .= "<div id=\"dh_$sId\" class=\"DrawerHandle\">".Dict::S('UI:SearchToggle')."</div>\n";
|
||||||
$iSearchSectionId++;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'open_flash_chart':
|
case 'open_flash_chart':
|
||||||
@@ -868,7 +875,7 @@ EOF
|
|||||||
*/
|
*/
|
||||||
class HistoryBlock extends DisplayBlock
|
class HistoryBlock extends DisplayBlock
|
||||||
{
|
{
|
||||||
public function GetRenderContent(WebPage $oPage, $aExtraParams = array())
|
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
|
||||||
{
|
{
|
||||||
$sHtml = '';
|
$sHtml = '';
|
||||||
$oSet = new CMDBObjectSet($this->m_oFilter, array('date'=>false));
|
$oSet = new CMDBObjectSet($this->m_oFilter, array('date'=>false));
|
||||||
@@ -950,7 +957,7 @@ class MenuBlock extends DisplayBlock
|
|||||||
* an object in with the same tab active by default as the tab that was active when selecting
|
* an object in with the same tab active by default as the tab that was active when selecting
|
||||||
* the "Modify..." action.
|
* the "Modify..." action.
|
||||||
*/
|
*/
|
||||||
public function GetRenderContent(WebPage $oPage, $aExtraParams = array())
|
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
|
||||||
{
|
{
|
||||||
$sHtml = '';
|
$sHtml = '';
|
||||||
$oAppContext = new ApplicationContext();
|
$oAppContext = new ApplicationContext();
|
||||||
|
|||||||
185
application/ui.autocompletewidget.class.inc.php
Normal file
185
application/ui.autocompletewidget.class.inc.php
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
<?php
|
||||||
|
// Copyright (C) 2010 Combodo SARL
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; version 3 of the License.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
/**
|
||||||
|
* Class UIAutoCompleteWidget
|
||||||
|
* UI wdiget for displaying and editing external keys when
|
||||||
|
* A simple drop-down list is not enough...
|
||||||
|
*
|
||||||
|
* The layout is the following
|
||||||
|
*
|
||||||
|
* +-- #label_<id> (input)-------+ +-----------+
|
||||||
|
* | | | Browse... |
|
||||||
|
* +-----------------------------+ +-----------+
|
||||||
|
*
|
||||||
|
* And the popup dialog has the following layout:
|
||||||
|
*
|
||||||
|
* +------------------- ac_dlg_<id> (div)-----------+
|
||||||
|
* + +--- ds_<id> (div)---------------------------+ |
|
||||||
|
* | | +------------- fs_<id> (form)------------+ | |
|
||||||
|
* | | | +--------+---+ | | |
|
||||||
|
* | | | | Class | V | | | |
|
||||||
|
* | | | +--------+---+ | | |
|
||||||
|
* | | | | | |
|
||||||
|
* | | | S e a r c h F o r m | | |
|
||||||
|
* | | | +--------+ | | |
|
||||||
|
* | | | | Search | | | |
|
||||||
|
* | | | +--------+ | | |
|
||||||
|
* | | +----------------------------------------+ | |
|
||||||
|
* | +--------------+-dh_<id>-+--------------------+ |
|
||||||
|
* | \ Search / |
|
||||||
|
* | +------+ |
|
||||||
|
* | +--- fr_<id> (form)--------------------------+ |
|
||||||
|
* | | +------------ dr_<id> (div)--------------+ | |
|
||||||
|
* | | | | | |
|
||||||
|
* | | | S e a r c h R e s u l t s | | |
|
||||||
|
* | | | | | |
|
||||||
|
* | | +----------------------------------------+ | |
|
||||||
|
* | | +--------+ +-----+ | |
|
||||||
|
* | | | Cancel | | Add | | |
|
||||||
|
* | | +--------+ +-----+ | |
|
||||||
|
* | +--------------------------------------------+ |
|
||||||
|
* +------------------------------------------------+
|
||||||
|
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||||
|
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||||
|
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||||
|
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once('../application/webpage.class.inc.php');
|
||||||
|
require_once('../application/displayblock.class.inc.php');
|
||||||
|
|
||||||
|
class UIAutoCompleteWidget
|
||||||
|
{
|
||||||
|
protected static $iWidgetIndex = 0;
|
||||||
|
protected $sAttCode;
|
||||||
|
protected $sNameSuffix;
|
||||||
|
protected $iId;
|
||||||
|
protected $sTitle;
|
||||||
|
|
||||||
|
public function __construct($sAttCode, $sClass, $sTitle, $aAllowedValues, $value, $iInputId, $sNameSuffix = '', $sFieldPrefix = '')
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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())
|
||||||
|
{
|
||||||
|
if ($this->oAttDef->IsNull($this->value)) // Null values are displayed as ''
|
||||||
|
{
|
||||||
|
$sDisplayValue = '';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$sDisplayValue = $this->GetObjectName($this->value);
|
||||||
|
}
|
||||||
|
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||||
|
$oPage->add_ready_script(
|
||||||
|
<<<EOF
|
||||||
|
oACWidget_{$this->iId} = new AutocompleteWidget('$this->iId', '$this->sClass', '$this->sAttCode', '$this->sNameSuffix');
|
||||||
|
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\"/> <a class=\"no-arrow\" href=\"javascript:oACWidget_{$this->iId}.Search();\"><img style=\"border:0;vertical-align:middle;\" src=\"../images/mini_search.gif\" /></a> <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";
|
||||||
|
|
||||||
|
// Scripts to start the autocomplete and bind some events to it
|
||||||
|
$oPage->add_ready_script("\$('#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."'}});");
|
||||||
|
$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_at_the_end($this->GetSearchDialog($oPage)); // To prevent adding forms inside the main form
|
||||||
|
|
||||||
|
return $sHTMLValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function GetSearchDialog(WebPage $oPage)
|
||||||
|
{
|
||||||
|
$sHTML = '<div id="ac_dlg_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">';
|
||||||
|
|
||||||
|
$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 .= "<form id=\"fr_{$this->iId}\" OnSubmit=\"return oACWidget_{$this->iId}.DoOk();\">\n";
|
||||||
|
$sHTML .= "<div id=\"dr_{$this->iId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
|
||||||
|
$sHTML .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
|
||||||
|
$sHTML .= "</div>\n";
|
||||||
|
$sHTML .= "<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ac_dlg_{$this->iId}').dialog('close');\"> ";
|
||||||
|
$sHTML .= "<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoOk();\">";
|
||||||
|
$sHTML .= "</div>\n";
|
||||||
|
$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("$('#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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -45,6 +45,7 @@ class WebPage
|
|||||||
protected $a_include_stylesheets;
|
protected $a_include_stylesheets;
|
||||||
protected $a_headers;
|
protected $a_headers;
|
||||||
protected $a_base;
|
protected $a_base;
|
||||||
|
protected $iNextId;
|
||||||
|
|
||||||
public function __construct($s_title)
|
public function __construct($s_title)
|
||||||
{
|
{
|
||||||
@@ -57,6 +58,7 @@ class WebPage
|
|||||||
$this->a_linked_stylesheets = array();
|
$this->a_linked_stylesheets = array();
|
||||||
$this->a_headers = array();
|
$this->a_headers = array();
|
||||||
$this->a_base = array( 'href' => '', 'target' => '');
|
$this->a_base = array( 'href' => '', 'target' => '');
|
||||||
|
$this->iNextId = 0;
|
||||||
ob_start(); // Start capturing the output
|
ob_start(); // Start capturing the output
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,5 +360,14 @@ class WebPage
|
|||||||
}
|
}
|
||||||
return $sTag;
|
return $sTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an ID (for any kind of HTML tag) that is guaranteed unique in this page
|
||||||
|
* @return int The unique ID (in this page)
|
||||||
|
*/
|
||||||
|
public function GetUniqueId()
|
||||||
|
{
|
||||||
|
return $this->iNextId++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -262,11 +262,11 @@ abstract class AttributeDefinition
|
|||||||
return (string)$sValue;
|
return (string)$sValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetAllowedValues($aArgs = array(), $sBeginsWith = '')
|
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||||
{
|
{
|
||||||
$oValSetDef = $this->GetValuesDef();
|
$oValSetDef = $this->GetValuesDef();
|
||||||
if (!$oValSetDef) return null;
|
if (!$oValSetDef) return null;
|
||||||
return $oValSetDef->GetValues($aArgs, $sBeginsWith);
|
return $oValSetDef->GetValues($aArgs, $sContains);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1295,9 +1295,9 @@ class AttributeEnum extends AttributeString
|
|||||||
return $sLabel;
|
return $sLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetAllowedValues($aArgs = array(), $sBeginsWith = '')
|
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||||
{
|
{
|
||||||
$aRawValues = parent::GetAllowedValues($aArgs, $sBeginsWith);
|
$aRawValues = parent::GetAllowedValues($aArgs, $sContains);
|
||||||
if (is_null($aRawValues)) return null;
|
if (is_null($aRawValues)) return null;
|
||||||
$aLocalizedValues = array();
|
$aLocalizedValues = array();
|
||||||
foreach ($aRawValues as $sKey => $sValue)
|
foreach ($aRawValues as $sKey => $sValue)
|
||||||
@@ -1729,17 +1729,17 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
|||||||
return $oValSetDef;
|
return $oValSetDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetAllowedValues($aArgs = array(), $sBeginsWith = '')
|
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return parent::GetAllowedValues($aArgs, $sBeginsWith);
|
return parent::GetAllowedValues($aArgs, $sContains);
|
||||||
}
|
}
|
||||||
catch (MissingQueryArgument $e)
|
catch (MissingQueryArgument $e)
|
||||||
{
|
{
|
||||||
// Some required arguments could not be found, enlarge to any existing value
|
// Some required arguments could not be found, enlarge to any existing value
|
||||||
$oValSetDef = new ValueSetObjects('SELECT '.$this->GetTargetClass());
|
$oValSetDef = new ValueSetObjects('SELECT '.$this->GetTargetClass());
|
||||||
return $oValSetDef->GetValues($aArgs, $sBeginsWith);
|
return $oValSetDef->GetValues($aArgs, $sContains);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1765,6 +1765,16 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
|||||||
if (MetaModel::IsValidObject($proposedValue)) return $proposedValue->GetKey();
|
if (MetaModel::IsValidObject($proposedValue)) return $proposedValue->GetKey();
|
||||||
return (int)$proposedValue;
|
return (int)$proposedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function GetMaximumComboLength()
|
||||||
|
{
|
||||||
|
return $this->GetOptional('max_combo_length', utils::GetConfig()->Get('max_combo_length'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetMinAutoCompleteChars()
|
||||||
|
{
|
||||||
|
return $this->GetOptional('min_autocomplete_chars', utils::GetConfig()->Get('min_autocomplete_chars'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -118,6 +118,22 @@ class Config
|
|||||||
'source_of_value' => '',
|
'source_of_value' => '',
|
||||||
'show_in_conf_sample' => true,
|
'show_in_conf_sample' => true,
|
||||||
),
|
),
|
||||||
|
'max_combo_length' => array(
|
||||||
|
'type' => 'int',
|
||||||
|
'description' => 'The maximum number of elements in a drop-down list. If more then an autocomplete will be used',
|
||||||
|
'default' => 50,
|
||||||
|
'value' => 50,
|
||||||
|
'source_of_value' => '',
|
||||||
|
'show_in_conf_sample' => false,
|
||||||
|
),
|
||||||
|
'min_autocomplete_chars' => array(
|
||||||
|
'type' => 'int',
|
||||||
|
'description' => 'The minimum number of characters to type in order to trigger the "autocomplete" behavior',
|
||||||
|
'default' => 3,
|
||||||
|
'value' => 3,
|
||||||
|
'source_of_value' => '',
|
||||||
|
'show_in_conf_sample' => false,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
public function IsProperty($sPropCode)
|
public function IsProperty($sPropCode)
|
||||||
|
|||||||
@@ -198,10 +198,10 @@ class FilterFromAttribute extends FilterDefinition
|
|||||||
return $oAttDef->GetValuesDef();
|
return $oAttDef->GetValuesDef();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetAllowedValues($aArgs = array(), $sBeginsWith = '')
|
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||||
{
|
{
|
||||||
$oAttDef = $this->Get("refattribute");
|
$oAttDef = $this->Get("refattribute");
|
||||||
return $oAttDef->GetAllowedValues($aArgs, $sBeginsWith);
|
return $oAttDef->GetAllowedValues($aArgs, $sContains);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetOperators()
|
public function GetOperators()
|
||||||
|
|||||||
@@ -902,16 +902,16 @@ abstract class MetaModel
|
|||||||
// Allowed values
|
// Allowed values
|
||||||
//
|
//
|
||||||
|
|
||||||
public static function GetAllowedValues_att($sClass, $sAttCode, $aArgs = array(), $sBeginsWith = '')
|
public static function GetAllowedValues_att($sClass, $sAttCode, $aArgs = array(), $sContains = '')
|
||||||
{
|
{
|
||||||
$oAttDef = self::GetAttributeDef($sClass, $sAttCode);
|
$oAttDef = self::GetAttributeDef($sClass, $sAttCode);
|
||||||
return $oAttDef->GetAllowedValues($aArgs, $sBeginsWith);
|
return $oAttDef->GetAllowedValues($aArgs, $sContains);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function GetAllowedValues_flt($sClass, $sFltCode, $aArgs = array(), $sBeginsWith = '')
|
public static function GetAllowedValues_flt($sClass, $sFltCode, $aArgs = array(), $sContains = '')
|
||||||
{
|
{
|
||||||
$oFltDef = self::GetClassFilterDef($sClass, $sFltCode);
|
$oFltDef = self::GetClassFilterDef($sClass, $sFltCode);
|
||||||
return $oFltDef->GetAllowedValues($aArgs, $sBeginsWith);
|
return $oFltDef->GetAllowedValues($aArgs, $sContains);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -51,25 +51,23 @@ abstract class ValueSetDefinition
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function GetValues($aArgs, $sBeginsWith = '')
|
public function GetValues($aArgs, $sContains = '')
|
||||||
{
|
{
|
||||||
if (!$this->m_bIsLoaded)
|
if (!$this->m_bIsLoaded)
|
||||||
{
|
{
|
||||||
$this->LoadValues($aArgs);
|
$this->LoadValues($aArgs);
|
||||||
$this->m_bIsLoaded = true;
|
$this->m_bIsLoaded = true;
|
||||||
}
|
}
|
||||||
if (strlen($sBeginsWith) == 0)
|
if (strlen($sContains) == 0)
|
||||||
{
|
{
|
||||||
$aRet = $this->m_aValues;
|
$aRet = $this->m_aValues;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$iCheckedLen = strlen($sBeginsWith);
|
|
||||||
$sBeginsWith = strtolower($sBeginsWith);
|
|
||||||
$aRet = array();
|
$aRet = array();
|
||||||
foreach ($this->m_aValues as $sKey=>$sValue)
|
foreach ($this->m_aValues as $sKey=>$sValue)
|
||||||
{
|
{
|
||||||
if (strtolower(substr($sValue, 0, $iCheckedLen)) == $sBeginsWith)
|
if (stripos($sValue, $sContains) !== false)
|
||||||
{
|
{
|
||||||
$aRet[$sKey] = $sValue;
|
$aRet[$sKey] = $sValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -886,4 +886,7 @@ tr.row_modified td {
|
|||||||
tr.row_added td {
|
tr.row_added td {
|
||||||
border-bottom: 1px #ccc solid;
|
border-bottom: 1px #ccc solid;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
|
}
|
||||||
|
a.truncated {
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
BIN
images/mini_search.gif
Normal file
BIN
images/mini_search.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 148 B |
177
js/autocompletewidget.js
Normal file
177
js/autocompletewidget.js
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
// Copyright (C) 2010 Combodo SARL
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; version 3 of the License.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
this.sClass = sClass;
|
||||||
|
this.sAttCode = sAttCode;
|
||||||
|
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
|
||||||
|
var me = this;
|
||||||
|
this.Init = function()
|
||||||
|
{
|
||||||
|
// make sure that the form is clean
|
||||||
|
$('#linkedset_'+this.id+' .selection').each( function() { this.checked = false; });
|
||||||
|
$('#'+this.id+'_btnRemove').attr('disabled','disabled');
|
||||||
|
$('#'+this.id+'_linksToRemove').val('');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Search = function()
|
||||||
|
{
|
||||||
|
$('#ac_dlg_'+me.id).dialog('open');
|
||||||
|
this.UpdateSizes();
|
||||||
|
this.UpdateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.UpdateSizes = function()
|
||||||
|
{
|
||||||
|
var dlg = $('#ac_dlg_'+me.id);
|
||||||
|
var searchForm = dlg.find('div.display_block:first'); // Top search form, enclosing display_block
|
||||||
|
var results = $('#dr_'+me.id);
|
||||||
|
padding_right = parseInt(dlg.css('padding-right').replace('px', ''));
|
||||||
|
padding_left = parseInt(dlg.css('padding-left').replace('px', ''));
|
||||||
|
padding_top = parseInt(dlg.css('padding-top').replace('px', ''));
|
||||||
|
padding_bottom = parseInt(dlg.css('padding-bottom').replace('px', ''));
|
||||||
|
width = dlg.innerWidth() - padding_right - padding_left - 22; // 5 (margin-left) + 5 (padding-left) + 5 (padding-right) + 5 (margin-right) + 2 for rounding !
|
||||||
|
height = dlg.innerHeight() - padding_top - padding_bottom -22;
|
||||||
|
form_height = searchForm.outerHeight();
|
||||||
|
results.height(height - form_height - 40); // Leave some space for the buttons
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.UpdateButtons = function()
|
||||||
|
{
|
||||||
|
var okBtn = $('#btn_ok_'+me.id);
|
||||||
|
if ($('#fr_'+me.id+' input[name=selectObject]:checked').length > 0)
|
||||||
|
{
|
||||||
|
okBtn.attr('disabled', '');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
okBtn.attr('disabled', 'disabled');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ajax_request = null;
|
||||||
|
|
||||||
|
this.DoSearchObjects = function(id)
|
||||||
|
{
|
||||||
|
var theMap = { sAttCode: me.sAttCode,
|
||||||
|
iInputId: me.id,
|
||||||
|
sSuffix: me.sSuffix,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gather the parameters from the search form
|
||||||
|
$('#fs_'+me.id+' :input').each(
|
||||||
|
function(i)
|
||||||
|
{
|
||||||
|
if (this.name != '')
|
||||||
|
{
|
||||||
|
theMap[this.name] = this.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
oWizardHelper.UpdateWizard();
|
||||||
|
theMap['json'] = oWizardHelper.ToJSON();
|
||||||
|
|
||||||
|
theMap['sRemoteClass'] = theMap['class']; // swap 'class' (defined in the form) and 'remoteClass'
|
||||||
|
theMap['class'] = me.sClass;
|
||||||
|
theMap.operation = 'searchObjectsToSelect'; // Override what is defined in the form itself
|
||||||
|
|
||||||
|
sSearchAreaId = '#dr_'+me.id;
|
||||||
|
//$(sSearchAreaId).html('<div style="text-align:center;width:100%;height:24px;vertical-align:middle;"><img src="../images/indicator.gif" /></div>');
|
||||||
|
$(sSearchAreaId).block();
|
||||||
|
me.UpdateButtons();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the query and display the results
|
||||||
|
ajax_request = $.post( 'ajax.render.php', theMap,
|
||||||
|
function(data)
|
||||||
|
{
|
||||||
|
$(sSearchAreaId).html(data);
|
||||||
|
$(sSearchAreaId+' .listResults').tableHover();
|
||||||
|
$(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;
|
||||||
|
},
|
||||||
|
'html'
|
||||||
|
);
|
||||||
|
|
||||||
|
return false; // Don't submit the form, stay in the current page !
|
||||||
|
}
|
||||||
|
|
||||||
|
this.DoOk = function()
|
||||||
|
{
|
||||||
|
var iObjectId = $('#fr_'+me.id+' input[name=selectObject]:checked').val();
|
||||||
|
$('#ac_dlg_'+this.id).dialog('close');
|
||||||
|
$('#label_'+this.id).addClass('ac_loading');
|
||||||
|
|
||||||
|
// Query the server again to get the display name of the selected object
|
||||||
|
var theMap = { sAttCode: me.sAttCode,
|
||||||
|
iInputId: me.id,
|
||||||
|
iObjectId: iObjectId,
|
||||||
|
sSuffix: me.sSuffix,
|
||||||
|
'class': me.sClass,
|
||||||
|
operation: 'getObjectName'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the query and get the result back directly in JSON
|
||||||
|
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;
|
||||||
|
},
|
||||||
|
'json'
|
||||||
|
);
|
||||||
|
|
||||||
|
return false; // Do NOT submit the form in case we are called by OnSubmit...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Workaround for a ui.jquery limitation: if the content of
|
||||||
|
// the dialog contains many INPUTs, closing and opening the
|
||||||
|
// dialog is very slow. So empty it each time.
|
||||||
|
this.OnClose = function()
|
||||||
|
{
|
||||||
|
// called by the dialog, so in the context 'this' points to the jQueryObject
|
||||||
|
if (me.emptyOnClose)
|
||||||
|
{
|
||||||
|
$('#dr_'+me.id).html(me.emptyHtml);
|
||||||
|
}
|
||||||
|
$('#label_'+me.id).focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
80
js/utils.js
80
js/utils.js
@@ -1,35 +1,54 @@
|
|||||||
// Some general purpose JS functions for the iTop application
|
// Some general purpose JS functions for the iTop application
|
||||||
/**
|
/**
|
||||||
* Reload a truncated list
|
* Reload a truncated list
|
||||||
*/
|
*/
|
||||||
|
aTruncatedLists = {}; // To keep track of the list being loaded, each member is an ajaxRequest object
|
||||||
|
|
||||||
function ReloadTruncatedList(divId, sSerializedFilter, sExtraParams)
|
function ReloadTruncatedList(divId, sSerializedFilter, sExtraParams)
|
||||||
{
|
{
|
||||||
$('#'+divId).addClass('loading');
|
$('#'+divId).block();
|
||||||
//$('#'+divId).blockUI();
|
//$('#'+divId).blockUI();
|
||||||
$.post('ajax.render.php?style=list',
|
if (aTruncatedLists[divId] != undefined)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
aAjaxRequest = aTruncatedLists[divId];
|
||||||
|
aAjaxRequest.abort();
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
// Do nothing special, just continue
|
||||||
|
console.log('Uh,uh, exception !');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aTruncatedLists[divId] = $.post('ajax.render.php?style=list',
|
||||||
{ operation: 'ajax', filter: sSerializedFilter, extra_params: sExtraParams },
|
{ operation: 'ajax', filter: sSerializedFilter, extra_params: sExtraParams },
|
||||||
function(data){
|
function(data)
|
||||||
$('#'+divId).empty();
|
{
|
||||||
$('#'+divId).append(data);
|
aTruncatedLists[divId] = undefined;
|
||||||
$('#'+divId).removeClass('loading');
|
if (data.length > 0)
|
||||||
$('#'+divId+' .listResults').tableHover(); // hover tables
|
{
|
||||||
$('#'+divId+' .listResults').each( function()
|
$('#'+divId).html(data);
|
||||||
{
|
$('#'+divId+' .listResults').tableHover(); // hover tables
|
||||||
var table = $(this);
|
$('#'+divId+' .listResults').each( function()
|
||||||
var id = $(this).parent();
|
|
||||||
var checkbox = (table.find('th:first :checkbox').length > 0);
|
|
||||||
if (checkbox)
|
|
||||||
{
|
{
|
||||||
// There is a checkbox in the first column, don't make it sortable
|
var table = $(this);
|
||||||
table.tablesorter( { headers: { 0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
var id = $(this).parent();
|
||||||
}
|
aTruncatedLists[divId] = undefined;
|
||||||
else
|
var checkbox = (table.find('th:first :checkbox').length > 0);
|
||||||
{
|
if (checkbox)
|
||||||
// There is NO checkbox in the first column, all columns are considered sortable
|
{
|
||||||
table.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
// There is a checkbox in the first column, don't make it sortable
|
||||||
}
|
table.tablesorter( { headers: { 0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||||
});
|
}
|
||||||
//$('#'+divId).unblockUI();
|
else
|
||||||
|
{
|
||||||
|
// There is NO checkbox in the first column, all columns are considered sortable
|
||||||
|
table.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('#'+divId).unblock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -38,6 +57,7 @@ function ReloadTruncatedList(divId, sSerializedFilter, sExtraParams)
|
|||||||
*/
|
*/
|
||||||
function TruncateList(divId, iLimit, sNewLabel, sLinkLabel)
|
function TruncateList(divId, iLimit, sNewLabel, sLinkLabel)
|
||||||
{
|
{
|
||||||
|
$('#'+divId).block();
|
||||||
var iCount = 0;
|
var iCount = 0;
|
||||||
$('#'+divId+' table.listResults tr:gt('+iLimit+')').each( function(){
|
$('#'+divId+' table.listResults tr:gt('+iLimit+')').each( function(){
|
||||||
$(this).remove();
|
$(this).remove();
|
||||||
@@ -47,13 +67,14 @@ function TruncateList(divId, iLimit, sNewLabel, sLinkLabel)
|
|||||||
$('#'+divId+' table.listResults').addClass('truncated');
|
$('#'+divId+' table.listResults').addClass('truncated');
|
||||||
$('#trc_'+divId).html(sLinkLabel);
|
$('#trc_'+divId).html(sLinkLabel);
|
||||||
$('#'+divId+' .listResults').trigger("update"); // Reset the cache
|
$('#'+divId+' .listResults').trigger("update"); // Reset the cache
|
||||||
|
$('#'+divId).unblock();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Reload any block -- used for periodic auto-reload
|
* Reload any block -- used for periodic auto-reload
|
||||||
*/
|
*/
|
||||||
function ReloadBlock(divId, sStyle, sSerializedFilter, sExtraParams)
|
function ReloadBlock(divId, sStyle, sSerializedFilter, sExtraParams)
|
||||||
{
|
{
|
||||||
$('#'+divId).addClass('loading');
|
$('#'+divId).block();
|
||||||
//$('#'+divId).blockUI();
|
//$('#'+divId).blockUI();
|
||||||
$.post('ajax.render.php?style='+sStyle,
|
$.post('ajax.render.php?style='+sStyle,
|
||||||
{ operation: 'ajax', filter: sSerializedFilter, extra_params: sExtraParams },
|
{ operation: 'ajax', filter: sSerializedFilter, extra_params: sExtraParams },
|
||||||
@@ -101,11 +122,10 @@ function UpdateFileName(id, sNewFileName)
|
|||||||
*/
|
*/
|
||||||
function ReloadSearchForm(divId, sClassName, sBaseClass, sContext)
|
function ReloadSearchForm(divId, sClassName, sBaseClass, sContext)
|
||||||
{
|
{
|
||||||
var oDiv = $('#'+divId);
|
var oDiv = $('#ds_'+divId);
|
||||||
oDiv.block();
|
oDiv.block();
|
||||||
var oFormEvents = $('#'+divId+' form').data('events');
|
var oFormEvents = $('#ds_'+divId+' form').data('events');
|
||||||
var aSubmit = new Array();
|
|
||||||
|
|
||||||
// Save the submit handlers
|
// Save the submit handlers
|
||||||
aSubmit = new Array();
|
aSubmit = new Array();
|
||||||
if ( (oFormEvents != null) && (oFormEvents.submit != undefined))
|
if ( (oFormEvents != null) && (oFormEvents.submit != undefined))
|
||||||
@@ -123,7 +143,7 @@ function ReloadSearchForm(divId, sClassName, sBaseClass, sContext)
|
|||||||
oDiv.append(data);
|
oDiv.append(data);
|
||||||
if (aSubmit.length > 0)
|
if (aSubmit.length > 0)
|
||||||
{
|
{
|
||||||
var oForm = $('#'+divId+' form'); // Form was reloaded, recompute it
|
var oForm = $('#ds_'+divId+' form'); // Form was reloaded, recompute it
|
||||||
for(index = 0; index < aSubmit.length; index++)
|
for(index = 0; index < aSubmit.length; index++)
|
||||||
{
|
{
|
||||||
// Restore the previously bound submit handlers
|
// Restore the previously bound submit handlers
|
||||||
|
|||||||
@@ -729,6 +729,7 @@ try
|
|||||||
$oP->add_linked_script("../js/wizardhelper.js");
|
$oP->add_linked_script("../js/wizardhelper.js");
|
||||||
$oP->add_linked_script("../js/wizard.utils.js");
|
$oP->add_linked_script("../js/wizard.utils.js");
|
||||||
$oP->add_linked_script("../js/linkswidget.js");
|
$oP->add_linked_script("../js/linkswidget.js");
|
||||||
|
$oP->add_linked_script("../js/autocompletewidget.js");
|
||||||
$oP->add_linked_script("../js/jquery.blockUI.js");
|
$oP->add_linked_script("../js/jquery.blockUI.js");
|
||||||
$sClass = utils::ReadParam('class', '');
|
$sClass = utils::ReadParam('class', '');
|
||||||
$sClassLabel = MetaModel::GetName($sClass);
|
$sClassLabel = MetaModel::GetName($sClass);
|
||||||
@@ -778,6 +779,7 @@ try
|
|||||||
$oP->add_linked_script("../js/wizardhelper.js");
|
$oP->add_linked_script("../js/wizardhelper.js");
|
||||||
$oP->add_linked_script("../js/wizard.utils.js");
|
$oP->add_linked_script("../js/wizard.utils.js");
|
||||||
$oP->add_linked_script("../js/linkswidget.js");
|
$oP->add_linked_script("../js/linkswidget.js");
|
||||||
|
$oP->add_linked_script("../js/autocompletewidget.js");
|
||||||
$oP->add_linked_script("../js/jquery.blockUI.js");
|
$oP->add_linked_script("../js/jquery.blockUI.js");
|
||||||
|
|
||||||
$aArgs = utils::ReadParam('default', array());
|
$aArgs = utils::ReadParam('default', array());
|
||||||
@@ -941,6 +943,7 @@ try
|
|||||||
$oP->add_linked_script("../js/wizardhelper.js");
|
$oP->add_linked_script("../js/wizardhelper.js");
|
||||||
$oP->add_linked_script("../js/wizard.utils.js");
|
$oP->add_linked_script("../js/wizard.utils.js");
|
||||||
$oP->add_linked_script("../js/linkswidget.js");
|
$oP->add_linked_script("../js/linkswidget.js");
|
||||||
|
$oP->add_linked_script("../js/autocompletewidget.js");
|
||||||
$oP->add_linked_script("../js/jquery.blockUI.js");
|
$oP->add_linked_script("../js/jquery.blockUI.js");
|
||||||
$oP->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $oObj->GetName(), $sClassLabel));
|
$oP->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $oObj->GetName(), $sClassLabel));
|
||||||
$oP->add("<div class=\"page_header\">\n");
|
$oP->add("<div class=\"page_header\">\n");
|
||||||
@@ -1077,6 +1080,7 @@ try
|
|||||||
$oP->add_linked_script("../js/wizardhelper.js");
|
$oP->add_linked_script("../js/wizardhelper.js");
|
||||||
$oP->add_linked_script("../js/wizard.utils.js");
|
$oP->add_linked_script("../js/wizard.utils.js");
|
||||||
$oP->add_linked_script("../js/linkswidget.js");
|
$oP->add_linked_script("../js/linkswidget.js");
|
||||||
|
$oP->add_linked_script("../js/autocompletewidget.js");
|
||||||
$oP->add_linked_script("../js/jquery.blockUI.js");
|
$oP->add_linked_script("../js/jquery.blockUI.js");
|
||||||
$oP->set_title(Dict::Format('UI:CreationPageTitle_Class', $sClassLabel));
|
$oP->set_title(Dict::Format('UI:CreationPageTitle_Class', $sClassLabel));
|
||||||
$oP->add("<h1>".MetaModel::GetClassIcon($sClass)." ".Dict::Format('UI:CreationTitle_Class', $sClassLabel)."</h1>\n");
|
$oP->add("<h1>".MetaModel::GetClassIcon($sClass)." ".Dict::Format('UI:CreationTitle_Class', $sClassLabel)."</h1>\n");
|
||||||
@@ -1152,6 +1156,7 @@ try
|
|||||||
$oP->add_linked_script("../js/wizardhelper.js");
|
$oP->add_linked_script("../js/wizardhelper.js");
|
||||||
$oP->add_linked_script("../js/wizard.utils.js");
|
$oP->add_linked_script("../js/wizard.utils.js");
|
||||||
$oP->add_linked_script("../js/linkswidget.js");
|
$oP->add_linked_script("../js/linkswidget.js");
|
||||||
|
$oP->add_linked_script("../js/autocompletewidget.js");
|
||||||
$oP->add_linked_script("../js/jquery.blockUI.js");
|
$oP->add_linked_script("../js/jquery.blockUI.js");
|
||||||
$oP->add("<div class=\"page_header\">\n");
|
$oP->add("<div class=\"page_header\">\n");
|
||||||
$oP->add("<h1>$sActionLabel - <span class=\"hilite\">{$oObj->GetName()}</span></h1>\n");
|
$oP->add("<h1>$sActionLabel - <span class=\"hilite\">{$oObj->GetName()}</span></h1>\n");
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ require_once('../application/webpage.class.inc.php');
|
|||||||
require_once('../application/ajaxwebpage.class.inc.php');
|
require_once('../application/ajaxwebpage.class.inc.php');
|
||||||
require_once('../application/wizardhelper.class.inc.php');
|
require_once('../application/wizardhelper.class.inc.php');
|
||||||
require_once('../application/ui.linkswidget.class.inc.php');
|
require_once('../application/ui.linkswidget.class.inc.php');
|
||||||
|
require_once('../application/ui.autocompletewidget.class.inc.php');
|
||||||
|
|
||||||
require_once('../application/startup.inc.php');
|
require_once('../application/startup.inc.php');
|
||||||
require_once('../application/user.preferences.class.inc.php');
|
require_once('../application/user.preferences.class.inc.php');
|
||||||
@@ -68,6 +69,33 @@ switch($operation)
|
|||||||
$oWidget->SearchObjectsToAdd($oPage, $sRemoteClass, $aAlreadyLinked);
|
$oWidget->SearchObjectsToAdd($oPage, $sRemoteClass, $aAlreadyLinked);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// ui.autocompletewidget
|
||||||
|
case 'searchObjectsToSelect':
|
||||||
|
$sTargetClass = utils::ReadParam('sRemoteClass', '');
|
||||||
|
$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();
|
||||||
|
$aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, array('this' => $oObj));
|
||||||
|
$oWidget = new UIAutocompleteWidget($sAttCode, $sClass, '', $aAllowedValues, $oObj->Get($sAttCode), $iInputId, $sSuffix, '');
|
||||||
|
$oWidget->SearchObjectsToSelect($oPage, $sTargetClass);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// ui.autocompletewidget
|
||||||
|
case 'getObjectName':
|
||||||
|
$sTargetClass = utils::ReadParam('sTargetClass', '');
|
||||||
|
$sAttCode = utils::ReadParam('sAttCode', '');
|
||||||
|
$iInputId = utils::ReadParam('iInputId', '');
|
||||||
|
$iObjectId = utils::ReadParam('iObjectId', '');
|
||||||
|
$sSuffix = utils::ReadParam('sSuffix', '');
|
||||||
|
$oWidget = new UIAutocompleteWidget($sAttCode, $sClass, '', array(), '', $iInputId, $sSuffix, '');
|
||||||
|
$sName = $oWidget->GetObjectName($iObjectId);
|
||||||
|
echo json_encode(array('name' => $sName));
|
||||||
|
break;
|
||||||
|
|
||||||
// ui.linkswidget
|
// ui.linkswidget
|
||||||
case 'doAddObjects':
|
case 'doAddObjects':
|
||||||
$sAttCode = utils::ReadParam('sAttCode', '');
|
$sAttCode = utils::ReadParam('sAttCode', '');
|
||||||
@@ -78,7 +106,7 @@ switch($operation)
|
|||||||
$oWidget = new UILinksWidget($sClass, $sAttCode, $iInputId, $sSuffix, $bDuplicates);
|
$oWidget = new UILinksWidget($sClass, $sAttCode, $iInputId, $sSuffix, $bDuplicates);
|
||||||
$oWidget->DoAddObjects($oPage, $aLinkedObjectIds);
|
$oWidget->DoAddObjects($oPage, $aLinkedObjectIds);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'wizard_helper_preview':
|
case 'wizard_helper_preview':
|
||||||
$sJson = utils::ReadParam('json_obj', '');
|
$sJson = utils::ReadParam('json_obj', '');
|
||||||
$oWizardHelper = WizardHelper::FromJSON($sJson);
|
$oWizardHelper = WizardHelper::FromJSON($sJson);
|
||||||
@@ -109,7 +137,8 @@ switch($operation)
|
|||||||
$value = $oObj->Get($sAttCode);
|
$value = $oObj->Get($sAttCode);
|
||||||
$displayValue = $oObj->GetEditValue($sAttCode);
|
$displayValue = $oObj->GetEditValue($sAttCode);
|
||||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||||
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $value, $displayValue, $sId, '', 0, array('this' => $oObj));
|
$iFlags = MetaModel::GetAttributeFlags($sClass, $oObj->GetState(), $sAttCode);
|
||||||
|
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $value, $displayValue, $sId, '', $iFlags, array('this' => $oObj));
|
||||||
// Make sure that we immediatly validate the field when we reload it
|
// Make sure that we immediatly validate the field when we reload it
|
||||||
$oPage->add_ready_script("$('#$sId').trigger('validate');");
|
$oPage->add_ready_script("$('#$sId').trigger('validate');");
|
||||||
$oWizardHelper->SetAllowedValuesHtml($sAttCode, $sHTMLValue);
|
$oWizardHelper->SetAllowedValuesHtml($sAttCode, $sHTMLValue);
|
||||||
|
|||||||
Reference in New Issue
Block a user