";
+ $sFilter = addslashes($oAllowedValues->GetFilter()->ToOQL());
+ if($this->bSearchMode)
+ {
+ $sWizHelper = 'null';
+ $sWizHelperJSON = "''";
+ $sJSSearchMode = 'true';
+ }
+ else
+ {
+ if (isset($aArgs['wizHelper']))
+ {
+ $sWizHelper = $aArgs['wizHelper'];
+ }
+ else
+ {
+ $sWizHelper = 'oWizardHelper'.$sFormPrefix;
+ }
+ $sWizHelperJSON = $sWizHelper.'.UpdateWizardToJSON()';
+ $sJSSearchMode = 'false';
+ }
+ if (is_null($oAllowedValues))
+ {
+ throw new Exception('Implementation: null value for allowed values definition');
+ }
+ $oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData());
+ // Don't automatically launch the search if the table is huge
+ $bDoSearch = !utils::IsHighCardinality($this->sTargetClass);
+ $sJSDoSearch = $bDoSearch ? 'true' : 'false';
+
+ // We just need to compare the number of entries with MaxComboLength, so no need to get the real count.
+ if (!$oAllowedValues->CountExceeds($iMaxComboLength))
+ {
+ // Discrete list of values, use a SELECT or RADIO buttons depending on the config
+ $sHelpText = ''; //$this->oAttDef->GetHelpOnEdition();
+ //$sHTMLValue .= "
\n";
+ $aOptions = [];
+ $sDisplayValue = "";
+
+ $aOption = [];
+ $aOption['value'] = "";
+ $aOption['label'] = Dict::S('UI:SelectOne');
+ array_push($aOptions,$aOption);
+
+ $oAllowedValues->Rewind();
+ while($oObj = $oAllowedValues->Fetch())
+ {
+ $aOption=[];
+ $aOption['value'] = $oObj->GetKey();
+ $aOption['label'] = $oObj->GetName();//.'
';
+
+ if (($oAllowedValues->Count() == 1) && ($bMandatory == 'true') )
+ {
+ // When there is only once choice, select it by default
+ $sDisplayValue=$oObj->GetName();
+ if($value != $oObj->GetKey())
+ {
+ $oPage->add_ready_script(
+ <<
iId').attr('data-validate','dependencies');
+EOF
+ );
+ }
+ }
+ else
+ {
+ if ((is_array($value) && in_array($oObj->GetKey(), $value)) || ($value == $oObj->GetKey()))
+ {
+ $sDisplayValue=$oObj->GetKey();
+ // $sHTMLValue.="".$oObj->GetName()."
";
+ }
+ }
+ if ($oObj->IsObsolete()){
+ $aOption['obsolescence_flag'] ="1";
+ }
+ array_push($aOptions,$aOption);
+ }
+ $sHTMLValue .= "";
+ $sJsonOptions=json_encode($aOptions);
+ $oPage->add_ready_script(
+ <<iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
+ oACWidget_{$this->iId}.emptyHtml = "";
+ oACWidget_{$this->iId}.AddSelectize('$sJsonOptions','$sDisplayValue');
+ $('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
+ $('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } );
+
+JS
+ );
+ }
+ else
+ {
+ // Too many choices, use an autocomplete
+ // Check that the given value is allowed
+ $oSearch = $oAllowedValues->GetFilter();
+ $oSearch->AddCondition('id', $value);
+ $oSet = new DBObjectSet($oSearch);
+ if ($oSet->Count() == 0)
+ {
+ $value = null;
+ }
+
+ if (is_null($value) || ($value == 0)) // Null values are displayed as ''
+ {
+ $sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : '';
+ }
+ else
+ {
+ $sDisplayValue = $this->GetObjectName($value);
+ }
+ $iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 2; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
+
+ // the input for the auto-complete
+ $sHTMLValue .= "iId\" value=\"$sDisplayValue\"/>";
+ $sHTMLValue .= "iId}\" onClick=\"oACWidget_{$this->iId}.Search();\">
";
+
+ // another hidden input to store & pass the object's Id
+ $sHTMLValue .= "iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" />\n";
+
+ $JSSearchMode = $this->bSearchMode ? 'true' : 'false';
+ // Scripts to start the autocomplete and bind some events to it
+ $oPage->add_ready_script(
+ <<iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch);
+ oACWidget_{$this->iId}.emptyHtml = "";
+ oACWidget_{$this->iId}.AddAutocomplete($iMinChars, $sWizHelperJSON);
+ if ($('#ac_dlg_{$this->iId}').length == 0)
+ {
+ $('body').append('');
+ }
+JS
+ );
+ }
+ if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
+ {
+ $sHTMLValue .= "iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\">
";
+ $oPage->add_ready_script(
+ <<iId}').length == 0)
+ {
+ $('body').append('');
+ }
+JS
+ );
+ }
+ if ($bCreate && $bExtensions)
+ {
+ $sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject';
+
+ $sHTMLValue .= "iId}\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\">
";
+ $oPage->add_ready_script(
+ <<iId}').length == 0)
+ {
+ $('body').append('');
+ }
+JS
+ );
+ }
+ $sHTMLValue .= "";
+
+ // Note: This test is no longer necessary as we changed the markup to extract validation decoration in the standard .field_input_xxx container
+ //if (($sDisplayStyle == 'select') || ($sDisplayStyle == 'list'))
+ //{
+ $sHTMLValue .= "
iId}\">iId}\">";
+ //}
+
+ return $sHTMLValue;
+ }
+
+ /**
+ * @since 2.8.0 N°2508 - Include Obsolescence icon within list and autocomplete
+ * Get the HTML fragment corresponding to the ext key editing widget
+ * @param WebPage $oP The web page used for all the output
+ * @param array $aArgs Extra context arguments
+ * @return string The HTML fragment to be inserted into the page
+ */
+ public function DisplayRadio(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, DBObjectset $oAllowedValues, $value, $sFieldName, $sDisplayStyle)
+ {
+ $oPage->add_linked_script('../js/forms-json-utils.js');
+
+ $bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
+ $bExtensions = true;
+ $sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_';
+
+ $sHTMLValue = "
";
+
+ // Note: This test is no longer necessary as we changed the markup to extract validation decoration in the standard .field_input_xxx container
+ //if (($sDisplayStyle == 'select') || ($sDisplayStyle == 'list'))
+ //{
+ $sHTMLValue .= "
iId}\">iId}\">";
+ //}
+
+ return $sHTMLValue;
+ }
+ /**
+ * @deprecated Use DisplayBob
* Get the HTML fragment corresponding to the ext key editing widget
* @param WebPage $oP The web page used for all the output
* @param array $aArgs Extra context arguments
@@ -440,12 +733,12 @@ EOF
$oValuesSet->SetSort(false);
$oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oValuesSet->SetLimit($iMax);
- $aValuesContains = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'start_with');
+ $aValuesContains = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'start_with');
asort($aValuesContains);
$aValues = $aValuesContains;
if (sizeof($aValues) < $iMax)
{
- $aValuesContains = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'contains');
+ $aValuesContains = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'contains');
asort($aValuesContains);
$iSize = sizeof($aValuesContains);
foreach ($aValuesContains as $sKey => $sFriendlyName)
@@ -462,7 +755,7 @@ EOF
}
elseif (!in_array($sContains, $aValues))
{
- $aValuesEquals = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'equals');
+ $aValuesEquals = $oValuesSet->GetValuesForAutocomplete(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'equals');
$aValues = array_merge($aValuesEquals, $aValues);
}
@@ -471,9 +764,9 @@ EOF
case static::ENUM_OUTPUT_FORMAT_JSON:
$aJsonMap = array();
- foreach ($aValues as $sKey => $sLabel)
+ foreach ($aValues as $sKey => $aValue)
{
- $aJsonMap[] = array('value' => $sKey, 'label' => $sLabel);
+ $aJsonMap[] = array('value' => $sKey, 'label' => $aValue['label'], 'obsolescence_flag' => $aValue['obsolescence_flag']);
}
$oP->SetContentType('application/json');
@@ -481,9 +774,9 @@ EOF
break;
case static::ENUM_OUTPUT_FORMAT_CSV:
- foreach($aValues as $sKey => $sFriendlyName)
+ foreach($aValues as $sKey => $aValue)
{
- $oP->add(trim($sFriendlyName)."\t".$sKey."\n");
+ $oP->add(trim($aValue['label'])."\t".$sKey."\n");
}
break;
default:
diff --git a/core/valuesetdef.class.inc.php b/core/valuesetdef.class.inc.php
index 0299f5c1e..ed4347e6b 100644
--- a/core/valuesetdef.class.inc.php
+++ b/core/valuesetdef.class.inc.php
@@ -220,7 +220,7 @@ class ValueSetObjects extends ValueSetDefinition
$this->m_sOperation = $sOperation;
$this->m_aValues = array();
-
+
if ($this->m_bAllowAllData)
{
$oFilter = DBObjectSearch::FromOQL_AllData($this->m_sFilterExpr);
@@ -348,6 +348,137 @@ class ValueSetObjects extends ValueSetDefinition
{
$this->m_bSort = $bSort;
}
+
+ public function GetValuesForAutocomplete($aArgs, $sContains = '', $sOperation = 'contains', $aAdditionalFields = array())
+ {
+ if (!$this->m_bIsLoaded || ($sContains != $this->m_sContains) || ($sOperation != $this->m_sOperation))
+ {
+ $this->LoadValuesForAutocomplete($aArgs, $sContains, $sOperation, $aAdditionalFields);
+ $this->m_bIsLoaded = true;
+ }
+ // The results are already filtered and sorted (on friendly name)
+ $aRet = $this->m_aValues;
+ return $aRet;
+ }
+
+ /**
+ * @param $aArgs
+ * @param string $sContains
+ * @param string $sOperation 'contains' or 'equals_start_with'
+ *
+ * @return bool
+ * @throws \CoreException
+ * @throws \OQLException
+ */
+ protected function LoadValuesForAutocomplete($aArgs, $sContains = '', $sOperation = 'contains', $aAdditionalFields = array())
+ {
+ $this->m_sContains = $sContains;
+ $this->m_sOperation = $sOperation;
+
+ $this->m_aValues = array();
+
+ if ($this->m_bAllowAllData)
+ {
+ $oFilter = DBObjectSearch::FromOQL_AllData($this->m_sFilterExpr);
+ }
+ else
+ {
+ $oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
+ $oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
+ }
+ if (!$oFilter) return false;
+ if (!is_null($this->m_oExtraCondition))
+ {
+ $oFilter = $oFilter->Intersect($this->m_oExtraCondition);
+ }
+ foreach($this->m_aModifierProperties as $sPluginClass => $aProperties)
+ {
+ foreach ($aProperties as $sProperty => $value)
+ {
+ $oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
+ }
+ }
+
+ $oExpression = DBObjectSearch::GetPolymorphicExpression($oFilter->GetClass(), 'friendlyname');
+ $sClass = $oFilter->GetClass();
+
+ switch ($sOperation)
+ {
+ case 'equals':
+ $aAttributes = MetaModel::GetFriendlyNameAttributeCodeList($sClass);
+ $sClassAlias = $oFilter->GetClassAlias();
+ $aFilters = array();
+ $oValueExpr = new ScalarExpression($sContains);
+ foreach($aAttributes as $sAttribute)
+ {
+ $oNewFilter = $oFilter->DeepClone();
+ $oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
+ $oCondition = new BinaryExpression($oNameExpr, '=', $oValueExpr);
+ $oNewFilter->AddConditionExpression($oCondition);
+ $aFilters[] = $oNewFilter;
+ }
+ // Unions are much faster than OR conditions
+ $oFilter = new DBUnionSearch($aFilters);
+ break;
+ case 'start_with':
+ $aAttributes = MetaModel::GetFriendlyNameAttributeCodeList($sClass);
+ $sClassAlias = $oFilter->GetClassAlias();
+ $aFilters = array();
+ $oValueExpr = new ScalarExpression($sContains.'%');
+ foreach($aAttributes as $sAttribute)
+ {
+ $oNewFilter = $oFilter->DeepClone();
+ $oNameExpr = new FieldExpression($sAttribute, $sClassAlias);
+ $oCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
+ $oNewFilter->AddConditionExpression($oCondition);
+ $aFilters[] = $oNewFilter;
+ }
+ // Unions are much faster than OR conditions
+ $oFilter = new DBUnionSearch($aFilters);
+ break;
+
+ default:
+ $oValueExpr = new ScalarExpression('%'.$sContains.'%');
+ $oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
+ $oNewCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
+ $oFilter->AddConditionExpression($oNewCondition);
+ break;
+ }
+
+ $oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs, null, $this->m_iLimit, 0, $this->m_bSort);
+ if (empty($this->m_sValueAttCode))
+ {
+ $aAttToLoad = array($oFilter->GetClassAlias() => array('friendlyname'));
+ }
+ else
+ {
+ $aAttToLoad = array($oFilter->GetClassAlias() => array($this->m_sValueAttCode));
+ }
+ $aAttToLoad=array_merge($aAttToLoad,$aAdditionalFields);
+ $oObjects->OptimizeColumnLoad($aAttToLoad);
+ while ($oObject = $oObjects->Fetch())
+ {
+ $aData=[];
+ if (empty($this->m_sValueAttCode))
+ {
+ $aData['label'] = $oObject->GetName();
+ }
+ else
+ {
+ $aData['label'] = $oObject->Get($this->m_sValueAttCode);
+ }
+ if($oObject->IsObsolete())
+ {
+ $aData['obsolescence_flag']='1';
+ }
+ foreach ($aAdditionalFields as $sFieldName)
+ {
+ $aData[$sFieldName] = $oObject->Get($sFieldName);
+ }
+ $this->m_aValues[$oObject->GetKey()] = $aData;
+ }
+ return true;
+ }
}
diff --git a/js/extkeywidget.js b/js/extkeywidget.js
index 8a258437f..34e951e80 100644
--- a/js/extkeywidget.js
+++ b/js/extkeywidget.js
@@ -38,78 +38,121 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
$('#'+this.id+'_btnRemove').prop('disabled',true);
$('#'+this.id+'_linksToRemove').val('');
}
+ this.AddSelectize = function(options, initValue)
+ {
+ $('#'+me.id).selectize({
+ render: {
+ item: function(item) {
+ if ( item.obsolescence_flag == 1)
+ {
+ console.warn("ici");
+ val = '
'+item.label;
+ }
+ else
+ {
+ val = item.label;
+ }
+ return $("
")
+ .append(val);
+ },
+ option: function(item) {
+ console.warn(item);
+ console.warn(item.obsolescence_flag);
+ console.warn($.inArray(item, 'obsolescence_flag'));
+ if ( item.obsolescence_flag == 1)
+ {
+ console.warn("ici");
+ val = '
'+item.label;
+ }
+ else
+ {
+ val = item.label;
+ }
+ return $("
")
+ .append(val);
+ }
+ },
+ items:[initValue],
+ valueField: 'value',
+ labelField: 'label',
+ searchField: ['value'],
+ options:JSON.parse(options),
+ maxItems: 1,
+ });
+ }
this.AddAutocomplete = function(iMinChars, sWizHelperJSON)
{
var hasFocus = 0;
var cache = {};
$('#label_'+me.id).autocomplete({
- source: function (request, response) {
- term = request.term.toLowerCase().latinise().replace(/[\u0300-\u036f]/g, "");
+ source: function (request, response) {
+ term = request.term.toLowerCase().latinise().replace(/[\u0300-\u036f]/g, "");
- if (term in cache)
- {
- response(cache[term]);
- return;
- }
- if (term.indexOf(this.previous) >= 0 && cache[this.previous] != null && cache[this.previous].length < 120)
- {
- //we have already all the possibility in cache
- var data = [];
- $.each(cache[this.previous], function (key, value) {
- if (value.label.toLowerCase().latinise().replace(/[\u0300-\u036f]/g, "").indexOf(term) >= 0)
- {
- data.push(value);
- }
- });
- cache[term] = data;
- response(data);
- }
- else
- {
- $.post({
- url: GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
- dataType: "json",
- data: {
- q: request.term,
- operation: 'ac_extkey',
- sTargetClass: me.sTargetClass,
- sFilter: me.sFilter,
- bSearchMode: me.bSearchMode,
- sOutputFormat: 'json',
- json: function () {
- return sWizHelperJSON;
- }
- },
- success: function (data) {
- cache[term] = data;
- response(data);
- }
- });
-
- }
- },
- autoFocus: true,
- minLength: iMinChars,
- focus: function (event, ui) {
- // $('#label_$this->iId').val( ui.item.label );
- return false;
- },
- select: function (event, ui) {
- $('#'+me.id).val(ui.item.value);
- $('#label_'+me.id).val(ui.item.label);
- $('#'+me.id).trigger('validate');
- $('#'+me.id).trigger('extkeychange');
- $('#'+me.id).trigger('change');
- return false;
+ if (term in cache)
+ {
+ response(cache[term]);
+ return;
}
- })
- .autocomplete("instance")._renderItem = function (ul, item) {
+ if (term.indexOf(this.previous) >= 0 && cache[this.previous] != null && cache[this.previous].length < 120)
+ {
+ //we have already all the possibility in cache
+ var data = [];
+ $.each(cache[this.previous], function (key, value) {
+ if (value.label.toLowerCase().latinise().replace(/[\u0300-\u036f]/g, "").indexOf(term) >= 0)
+ {
+ data.push(value);
+ }
+ });
+ cache[term] = data;
+ response(data);
+ }
+ else
+ {
+ $.post({
+ url: GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
+ dataType: "json",
+ data: {
+ q: request.term,
+ operation: 'ac_extkey',
+ sTargetClass: me.sTargetClass,
+ sFilter: me.sFilter,
+ bSearchMode: me.bSearchMode,
+ sOutputFormat: 'json',
+ json: function () {
+ return sWizHelperJSON;
+ }
+ },
+ success: function (data) {
+ cache[term] = data;
+ response(data);
+ }
+ });
+
+ }
+ },
+ autoFocus: true,
+ minLength: iMinChars,
+ focus: function (event, ui) {
+ // $('#label_$this->iId').val( ui.item.label );
+ return false;
+ },
+ select: function (event, ui) {
+ $('#'+me.id).val(ui.item.value);
+ $('#label_'+me.id).val(ui.item.label);
+ $('#'+me.id).trigger('validate');
+ $('#'+me.id).trigger('extkeychange');
+ $('#'+me.id).trigger('change');
+ return false;
+ }
+ })
+ .autocomplete("instance")._renderItem = function (ul, item) {
var term = this.term.replace("/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi", "\\$1");
var val = item.label.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+term+")(?![^<>]*>)(?![^&;]+;)", "gi"), "$1");
- if (item.obsolete == 'yes')
+ if (item.obsolescence_flag == '1')
{
- val = val+' old';
+ val = ' '+val;
}
+ val=''+val+'';
return $("
")
.append(val)
.appendTo(ul);
diff --git a/sources/renderer/console/fieldrenderer/consoleselectobjectfieldrenderer.class.inc.php b/sources/renderer/console/fieldrenderer/consoleselectobjectfieldrenderer.class.inc.php
index 3012832e6..a96b1a5ee 100644
--- a/sources/renderer/console/fieldrenderer/consoleselectobjectfieldrenderer.class.inc.php
+++ b/sources/renderer/console/fieldrenderer/consoleselectobjectfieldrenderer.class.inc.php
@@ -91,11 +91,10 @@ class ConsoleSelectObjectFieldRenderer extends FieldRenderer
$sFormPrefix = '';
$oWidget = new \UIExtKeyWidget($sTargetClass, $sFieldId, '', true);
$aArgs = array();
- $sDisplayStyle = 'select';
$sTitle = $this->oField->GetLabel();
require_once(APPROOT.'application/capturewebpage.class.inc.php');
$oPage = new \CaptureWebPage();
- $sHTMLValue = $oWidget->Display($oPage, $iMaxComboLength, false /* $bAllowTargetCreation */, $sTitle, $oSet, $this->oField->GetCurrentValue(), $sFieldId, $this->oField->GetMandatory(), $sFieldName, $sFormPrefix, $aArgs, null, $sDisplayStyle);
+ $sHTMLValue = $oWidget->DisplaySelect($oPage, $iMaxComboLength, false /* $bAllowTargetCreation */, $sTitle, $oSet, $this->oField->GetCurrentValue(), $this->oField->GetMandatory(), $sFieldName, $sFormPrefix, $aArgs);
$oOutput->AddHtml($sHTMLValue);
$oOutput->AddHtml($oPage->GetHtml());
$oOutput->AddJs($oPage->GetJS());