mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-20 15:52:24 +02:00
Improved autocomplete field display
This commit is contained in:
204
pages/audit.php
204
pages/audit.php
@@ -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>";
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user