*
* @property \Combodo\iTop\Form\Field\SelectObjectField $oField
*/
class BsSelectObjectFieldRenderer extends BsFieldRenderer
{
/**
* @inheritDoc
*/
public function Render()
{
$oOutput = parent::Render();
$sFieldValueClass = $this->oField->GetSearch()->GetClass();
$sFieldMandatoryClass = ($this->oField->GetMandatory()) ? 'form_mandatory' : '';
$iFieldControlType = $this->oField->GetControlType();
$sFieldDescriptionForHTMLTag = ($this->oField->HasDescription()) ? 'data-tooltip-content="'.utils::HtmlEntities($this->oField->GetDescription()).'"' : '';
// TODO : Remove this when hierarchical search supported
$this->oField->SetHierarchical(false);
// Rendering field in edition mode
if (!$this->oField->GetReadOnly() && !$this->oField->GetHidden())
{
// Debug trace: This is very useful when this kind of field doesn't return the expected values.
if(ContextTag::Check('debug'))
{
IssueLog::Info('Form field #'.$this->oField->GetId().' OQL query: '.$this->oField->GetSearch()->ToOQL(true));
}
// Rendering field
// - Opening container
$oOutput->AddHtml('
');
// Label
$oOutput->AddHtml('
');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('');
}
$oOutput->AddHtml('
');
// Value
$oOutput->AddHtml('
');
$oOutput->AddHtml('');
// - As a select
// TODO : This should be changed when we do the radio button display. For now we display everything with select
//if ($iFieldControlType === SelectObjectField::CONTROL_SELECT)
if (true)
{
// Checking if regular select or autocomplete
$oSearch = $this->oField->GetSearch()->DeepClone();
$oCountSet = new DBObjectSet($oSearch);
$iSetCount = $oCountSet->Count();
// Note : Autocomplete/Search is disabled for template fields as they are not external keys, thus they will just be displayed as regular select.
$bRegularSelect = ( ($iSetCount < $this->oField->GetMaximumComboLength()) || ($this->oField->GetSearchEndpoint() === null) || ($this->oField->GetSearchEndpoint() === '') );
unset($oCountSet);
// - For regular select
if ($bRegularSelect)
{
// HTML for select part
// - Opening row
$oOutput->AddHtml('
');
// - Rendering select
$oOutput->AddHtml('
');
$oOutput->AddHtml('');
$oOutput->AddHtml('
');
// - Closing col for autocomplete & opening col for hierarchy, rendering hierarchy button, closing col and row
$oOutput->AddHtml('
');
// JS FieldChange trigger (:input are not always at the same depth)
$oOutput->AddJs(
<<oField->GetGlobalId()}").off("change keyup").on("change keyup", function(){
var me = this;
$(this).closest(".field_set").trigger("field_change", {
id: $(me).attr("id"),
name: $(me).closest(".form_field").attr("data-field-id"),
value: $(me).val()
});
});
EOF
);
// Attaching JS widget
$oOutput->AddJs(
<<oField->GetId()}'][data-form-path='{$this->oField->GetFormPath()}']").portal_form_field({
'validators': {$this->GetValidatorsAsJson()}
});
EOF
);
}
// - For autocomplete
else
{
$sAutocompleteFieldId = 's_ac_' . $this->oField->GetGlobalId();
$sEndpoint = str_replace('-sMode-', 'autocomplete', $this->oField->GetSearchEndpoint());
$sNoResultText = Dict::S('Portal:Autocomplete:NoResult');
// Retrieving field value
$currentValue = $this->oField->GetCurrentValue();
if (!empty($currentValue))
{
try
{
// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
$oFieldValue = MetaModel::GetObject($sFieldValueClass, $this->oField->GetCurrentValue(), true, true);
}
catch (CoreException $e)
{
IssueLog::Error('Could not retrieve object ' . $sFieldValueClass . '::' . $this->oField->GetCurrentValue() . ' for "' . $this->oField->GetId() . '" field.');
throw new Exception($e->getMessage(), $e->getCode(), $e->getPrevious());
}
$sFieldValue = $oFieldValue->GetName();
}
else
{
$sFieldValue = '';
}
// HTML for autocomplete part
// - Opening input group
$oOutput->AddHtml('
'
}
})
.off('typeahead:select').on('typeahead:select', function(oEvent, oSuggestion){
$('#{$this->oField->GetGlobalId()}').val(oSuggestion.id);
$('#{$sAutocompleteFieldId}').val(oSuggestion.name);
// Triggering set_current_value event
var oValue = {};
oValue[oSuggestion.id] = oSuggestion.name;
$("[data-field-id='{$this->oField->GetId()}'][data-form-path='{$this->oField->GetFormPath()}']").trigger('set_current_value', {value: oValue});
})
.off('typeahead:change').on('typeahead:change', function(oEvent, oSuggestion){
// Checking if the value is a correct value. This is necessary because the user could empty the field / remove some chars and typeahead would not update the hidden input
var oDatums = oAutocompleteSource_{$this->oField->GetId()}.index.datums;
var bFound = false;
for(var i in oDatums)
{
if(oDatums[i].name == oSuggestion)
{
bFound = true;
$('#{$this->oField->GetGlobalId()}').val(oDatums[i].id);
$('#{$sAutocompleteFieldId}').val(oDatums[i].name);
break;
}
}
// Emptying the fields if value is incorrect
if(!bFound)
{
$('#{$this->oField->GetGlobalId()}').val(0);
$('#{$sAutocompleteFieldId}').val('');
}
});
}
EOF
);
}
}
$oOutput->AddHtml('
');
// - Closing container
$oOutput->AddHtml('
');
}
// ... and in read-only mode (or hidden)
else
{
// Retrieving field value
if ($this->oField->GetCurrentValue() !== null && $this->oField->GetCurrentValue() !== 0 && $this->oField->GetCurrentValue() !== '')
{
// Note : AllowAllData set to true here instead of checking scope's flag because we are displaying a value that has been set and validated
$oFieldValue = MetaModel::GetObjectWithArchive($sFieldValueClass, $this->oField->GetCurrentValue(), true, true);
$sFieldHtmlValue = $oFieldValue->GetName();
if($oFieldValue->IsArchived())
{
$sFieldHtmlValue = '' . $sFieldHtmlValue;
}
else
{
$sFieldUrl = ApplicationContext::MakeObjectUrl($sFieldValueClass, $this->oField->GetCurrentValue());
if (!empty($sFieldUrl))
{
$sFieldHtmlValue = '' . $sFieldHtmlValue . '';
}
}
}
else
{
$sFieldHtmlValue = Dict::S('UI:UndefinedObject');
}
// Opening container
$oOutput->AddHtml('
');
// Showing label / value only if read-only but not hidden
if (!$this->oField->GetHidden())
{
// Label
$oOutput->AddHtml('
');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('');
}
$oOutput->AddHtml('