Improved autocomplete field display

This commit is contained in:
Anne-Cath
2024-12-04 11:43:48 +01:00
parent 25109a1a55
commit d361edf187

View File

@@ -162,8 +162,8 @@ function MakeSelectField($oPage, string $sLabel, string $sFieldName, string $sOq
$iMaxComboLength = MetaModel::GetConfig()->Get('max_combo_length'); $iMaxComboLength = MetaModel::GetConfig()->Get('max_combo_length');
$bIsAutocomplete = $oAllowedValues->CountExceeds($iMaxComboLength); $bIsAutocomplete = $oAllowedValues->CountExceeds($iMaxComboLength);
$sWrapperCssClass = $bIsAutocomplete ? 'ibo-input-select-autocomplete-wrapper' : 'ibo-input-select-wrapper'; $sWrapperCssClass = $bIsAutocomplete ? 'field_input_extkey ibo-input-wrapper ibo-input-select-wrapper--with-buttons ibo-input-select-autocomplete-wrapper' : 'ibo-input-select-wrapper';
$sHTMLValue = "<div class=\"field_input_zone\">"; $sHTMLValue = "<div class=\"field_input_zone $sWrapperCssClass\">";
// We just need to compare the number of entries with MaxComboLength, so no need to get the real count. // We just need to compare the number of entries with MaxComboLength, so no need to get the real count.
if (!$bIsAutocomplete) { if (!$bIsAutocomplete) {
@@ -263,210 +263,34 @@ JS
// another hidden input to store & pass the object's Id // another hidden input to store & pass the object's Id
$sHTMLValue .= "<input type=\"hidden\" id=\"$sFieldName\" name=\"{$sFieldName}\" value=\"".utils::HtmlEntities($sCurrentValue)."\" />\n"; $sHTMLValue .= "<input type=\"hidden\" id=\"$sFieldName\" name=\"{$sFieldName}\" value=\"".utils::HtmlEntities($sCurrentValue)."\" />\n";
// Scripts to start the autocomplete and bind some events to it $sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
$oPage->add_ready_script( $oPage->add_ready_script(
<<<JS <<<EOF
oACWidget_{$sFieldName} = new ExtKeyWidget('$sFieldName', '$sClass', '$sOql', '$sLabel', false, null, '{$sFieldName}', true, false);
var hasFocus = 0; oACWidget_{$sFieldName}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
var cache = {}; oACWidget_{$sFieldName}.AddAutocomplete($iMinChars, '');
$('#label_$sFieldName').data('selected_value', $('#label_$sFieldName').val());
$('#label_$sFieldName').attr('title', $('#label_$sFieldName').val());
$('#label_$sFieldName').autocomplete({
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: '$sClass',
sFilter: '$sOql',
bSearchMode: true,
sOutputFormat: 'json',
json: function () {
return '';
}
},
success: function (data) {
cache[term] = data;
response(data);
}
});
}
},
autoFocus: true,
minLength: $iMinChars,
focus: function (event, ui) {
return false;
},
select: function (event, ui) {
$('#$sFieldName').val(ui.item.value);
let labelValue = $('<div>').html(ui.item.label).text();
$('#label_$sFieldName').val(labelValue);
$('#label_$sFieldName').data('selected_value', labelValue);
$('#label_$sFieldName').attr('title',labelValue);
return false;
},
open: function (event, ui) {
// dialog tries to move above every .ui-front with _moveToTop(), we want to be above our parent dialog
var dialog = $(this).closest('.ui-dialog');
if (dialog.length > 0) {
$('.ui-autocomplete.ui-front').css('z-index', parseInt(dialog.css("z-index"))+1);
}
// UpdateDropdownPosition = function (oControlElem, oDropdownElem) {
// First fix width to ensure it's not too long
const fControlWidth = $(this).outerWidth();
$('.ui-autocomplete.selectize-dropdown:visible').css('width', fControlWidth);
// Then, fix height / position to ensure it's within the viewport
const fWindowHeight = window.innerHeight;
const fControlTopY = $(this).offset().top;
const fControlHeight = $(this).outerHeight();
const fDropdownTopY = $('.ui-autocomplete.selectize-dropdown:visible').offset().top;
// This one is "let" as it might be updated if necessary
let fDropdownHeight = $('.ui-autocomplete.selectize-dropdown:visible').outerHeight();
const fDropdownBottomY = fDropdownTopY + fDropdownHeight;
if (fDropdownBottomY > fWindowHeight) {
// Set dropdown max-height to 1/3 of the screen, this way we are sure the dropdown will fit in either the top / bottom half of the screen
$('.ui-autocomplete.selectize-dropdown:visible').css('max-height', '30vh');
fDropdownHeight = $('.ui-autocomplete.selectize-dropdown:visible').outerHeight();
// Position dropdown above input if not enough space on the bottom part of the screen
if ((fDropdownTopY / fWindowHeight) > 0.6) {
$('.ui-autocomplete.selectize-dropdown:visible').css('top', fDropdownTopY - fDropdownHeight - fControlHeight);
}
}
// this.ManageScroll = function () {
if ($('#label_$sFieldName').scrollParent()[0].tagName != 'HTML') {
$('#label_$sFieldName').scrollParent().on(['scroll.$sFieldName', 'resize.$sFieldName'].join(" "), function () {
setTimeout(function () {
me.ManageScrollInElement();
}, 50);
});
if ($('#label_$sFieldName').scrollParent().scrollParent()[0].tagName != 'HTML') {
$('#label_$sFieldName').scrollParent().scrollParent().on(['scroll.$sFieldName', 'resize.$sFieldName'].join(" "), function () {
setTimeout(function () {
me.ManageScrollInElement();
}, 50);
});
}
}
},
close: function (event, ui) {
if ($('#label_$sFieldName').scrollParent()[0].tagName != 'HTML') {
$('#label_$sFieldName').scrollParent().off('scroll.$sFieldName');
$('#label_$sFieldName').scrollParent().off('resize.$sFieldName');
if ($('#label_$sFieldName').scrollParent().scrollParent()[0].tagName != 'HTML') {
$('#label_$sFieldName').scrollParent().scrollParent().off('scroll.$sFieldName');
$('#label_$sFieldName').scrollParent().scrollParent().off('resize.$sFieldName');
}
}
}
})
.autocomplete("instance")._renderItem = function (ul, item) {
$(ul).addClass('selectize-dropdown');
let term = this.term.replace("/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi", "\\$1");
let val = '';
if (item.initials != undefined) {
if (item.picture_url != undefined) {
val = '<span class="ibo-input-select--autocomplete-item-image" style="background-image: url('+item.picture_url+');">'+item.initials+'</span>';
} else {
val = '<span class="ibo-input-select--autocomplete-item-image");">'+item.initials+'</span>';
}
}
val = val+'<div class="ibo-input-select--autocomplete-item-txt" title="'+item.label+'">';
if (item.obsolescence_flag == '1') {
val = val+' <span class="object-ref-icon text_decoration"><span class="fas fa-eye-slash object-obsolete fa-1x fa-fw"></span></span>';
}
let labelValue = item.label.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+term+")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
val = val+labelValue;
if (item.additional_field != undefined) {
val = val+'<br><i>'+item.additional_field+'</i>';
}
val = val+'</div>';
return $("<li>")
.append("<div data-selectable=\"\" class=\"ibo-input-select--autocomplete-item\">"+val+"</div>")
.appendTo(ul);
};
$('#label_$sFieldName').on('focus', function () {
// track whether the field has focus, we shouldn't process any
// results if the field no longer has focus
hasFocus++;
}).on('blur', function () {
hasFocus = 0;
if ($('#label_$sFieldName').val().length == 0) {
$('#$sFieldName').val('');
$('#label_$sFieldName').val('');
$('#label_$sFieldName').data('selected_value', '');
} else {
$('#label_$sFieldName').val($('#label_$sFieldName').data('selected_value'));
}
}).on('click',
function () {
hasFocus++;
$('#label_$sFieldName').autocomplete("search");
}).on('keyup',function () {
if ($('#label_$sFieldName').val().length == 0) {
if (!$('#label_$sFieldName').parent().find('.ibo-input-select--action-button--clear').hasClass('ibo-is-hidden')) {
$('#label_$sFieldName').parent().find('.ibo-input-select--action-button--clear').addClass('ibo-is-hidden');
}
} else {
if ($('#label_$sFieldName').parent().find('.ibo-input-select--action-button--clear').hasClass('ibo-is-hidden')) {
$('#label_$sFieldName').parent().find('.ibo-input-select--action-button--clear').removeClass('ibo-is-hidden');
}
}
});
var iPaddingRight = $('#$sFieldName').parent().find('.ibo-input-select--action-buttons')[0].childElementCount * 20+15;
$('#$sFieldName').parent().find('.ibo-input-select').css('padding-right', iPaddingRight);
if ($('#ac_dlg_{$sFieldName}').length == 0) if ($('#ac_dlg_{$sFieldName}').length == 0)
{ {
$('body').append('<div id="ac_dlg_{$sFieldName}"></div>'); $('body').append('<div id="ac_dlg_{$sFieldName}"></div>');
} }
JS EOF
); );
$sHTMLValue .= "<div class=\"ibo-input-select--action-buttons\">"; $sHTMLValue .= "<div class=\"ibo-input-select--action-buttons\">";
$sHTMLValue .= "<a href=\"#\" class=\"ibo-input-select--action-button ibo-input-select--action-button--clear ibo-is-hidden\" id=\"mini_clear_{$sFieldName}\" onClick=\"$('#$sFieldName').val('');$('#label_$sFieldName').val(''); $('#label_$sFieldName').data('selected_value', '');\" data-tooltip-content='".Dict::S('UI:Button:Clear')."'><i class=\"fas fa-times\"></i></a>"; $sHTMLValue .= "<a href=\"#\" class=\"ibo-input-select--action-button ibo-input-select--action-button--clear ibo-is-hidden\" id=\"mini_clear_{$sFieldName}\" onClick=\"$('#$sFieldName').val('');$('#label_$sFieldName').val(''); $('#label_$sFieldName').data('selected_value', '');\" data-tooltip-content='".Dict::S('UI:Button:Clear')."'><i class=\"fas fa-times\"></i></a>";
} $sHTMLValue .= "<a href=\"#\" class=\"ibo-input-select--action-button ibo-input-select--action-button--search\" id=\"mini_search_{$sFieldName}\" onClick=\"oACWidget_{$sFieldName}.Search();\" data-tooltip-content='".Dict::S('UI:Button:Search')."'><i class=\"fas fa-search\"></i></a>";
/* if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false) { if (MetaModel::IsHierarchicalClass($sClass) !== false) {
$sHTMLValue .= "<a href=\"#\" class=\"ibo-input-select--action-button ibo-input-select--action-button--hierarchy\" id=\"mini_tree_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\" data-tooltip-content='".Dict::S('UI:Button:SearchInHierarchy')."'><i class=\"fas fa-sitemap\"></i></a>"; $sHTMLValue .= "<a href=\"#\" class=\"ibo-input-select--action-button ibo-input-select--action-button--hierarchy\" id=\"mini_tree_{$sFieldName}\" onClick=\"oACWidget_{$sFieldName}.HKDisplay();\" data-tooltip-content='".Dict::S('UI:Button:SearchInHierarchy')."'><i class=\"fas fa-sitemap\"></i></a>";
$oPage->add_ready_script( $oPage->add_ready_script(
<<<JS <<<JS
if ($('#ac_tree_{$sFieldName}').length == 0) if ($('#ac_tree_{$sFieldName}').length == 0)
{ {
$('body').append('<div id="ac_tree_{$sFieldName}"></div>'); $('body').append('<div id="ac_tree_{$sFieldName}"></div>');
} }
JS JS
); );
} }
if ($oAllowedValues->CountExceeds($iMaxComboLength)) { }
$sHTMLValue .= " <a href=\"#\" class=\"ibo-input-select--action-button ibo-input-select--action-button--search\" id=\"mini_search_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.Search();\" data-tooltip-content='".Dict::S('UI:Button:Search')."'><i class=\"fas fa-search\"></i></a>";
}*/
$sHTMLValue .= "</div>"; $sHTMLValue .= "</div>";
$sHTMLValue .= "</div>"; $sHTMLValue .= "</div>";