Autosave: 20260428-225104
This commit is contained in:
parent
a4cb3a5abc
commit
a1559c3861
538
scitemcustom.php
538
scitemcustom.php
@ -46,6 +46,74 @@ function scitemcustom_display_value($value): string
|
||||
return $formatted === '' ? '0' : $formatted;
|
||||
}
|
||||
|
||||
function scitemcustom_escape_like(string $value): string
|
||||
{
|
||||
return strtr($value, [
|
||||
'\\' => '\\\\',
|
||||
'%' => '\\%',
|
||||
'_' => '\\_',
|
||||
]);
|
||||
}
|
||||
|
||||
function scitemcustom_search_available_items(PDO $db, int $ownerAuthId, string $query, int $limit = 15): array
|
||||
{
|
||||
$query = trim($query);
|
||||
if ($query === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$escapedQuery = scitemcustom_escape_like($query);
|
||||
$exact = $escapedQuery;
|
||||
$prefix = $escapedQuery . '%';
|
||||
$contains = '%' . $escapedQuery . '%';
|
||||
$limit = max(1, min(25, $limit));
|
||||
|
||||
$sql = "SELECT cl_scobjs_id, cl_scobjs_name, cl_scobjs_uuid, cl_scobjs_type, cl_scobjs_subtype
|
||||
FROM tbl_scobjs
|
||||
WHERE cl_scobjs_id NOT IN (
|
||||
SELECT cl_scitemcustom_obj_id
|
||||
FROM tbl_scitemcustom
|
||||
WHERE cl_scitemcustom_owner_auth_id = :owner_auth_id
|
||||
)
|
||||
AND (
|
||||
cl_scobjs_name LIKE :contains_name
|
||||
OR cl_scobjs_type LIKE :contains_type
|
||||
OR cl_scobjs_subtype LIKE :contains_subtype
|
||||
OR cl_scobjs_uuid LIKE :contains_uuid
|
||||
)
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN cl_scobjs_name = :exact_name THEN 0
|
||||
WHEN cl_scobjs_name LIKE :prefix_name THEN 1
|
||||
WHEN cl_scobjs_uuid = :exact_uuid THEN 2
|
||||
WHEN cl_scobjs_uuid LIKE :prefix_uuid THEN 3
|
||||
WHEN cl_scobjs_type LIKE :prefix_type THEN 4
|
||||
WHEN cl_scobjs_subtype LIKE :prefix_subtype THEN 5
|
||||
ELSE 6
|
||||
END ASC,
|
||||
CHAR_LENGTH(cl_scobjs_name) ASC,
|
||||
cl_scobjs_name ASC,
|
||||
cl_scobjs_id ASC
|
||||
LIMIT {$limit}";
|
||||
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->execute([
|
||||
'owner_auth_id' => $ownerAuthId,
|
||||
'contains_name' => $contains,
|
||||
'contains_type' => $contains,
|
||||
'contains_subtype' => $contains,
|
||||
'contains_uuid' => $contains,
|
||||
'exact_name' => $exact,
|
||||
'prefix_name' => $prefix,
|
||||
'exact_uuid' => $exact,
|
||||
'prefix_uuid' => $prefix,
|
||||
'prefix_type' => $prefix,
|
||||
'prefix_subtype' => $prefix,
|
||||
]);
|
||||
|
||||
return $stmt->fetchAll() ?: [];
|
||||
}
|
||||
|
||||
function scitemcustom_preview(string $sign, $value, string $unit): string
|
||||
{
|
||||
$prefix = $sign === '-' ? '-' : ($sign === '+' ? '+' : '');
|
||||
@ -300,28 +368,33 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
}
|
||||
|
||||
$search = trim($_GET['search'] ?? '');
|
||||
$search_results = [];
|
||||
if ($search !== '') {
|
||||
$stmt_search = $db->prepare(
|
||||
"SELECT *
|
||||
FROM tbl_scobjs
|
||||
WHERE (cl_scobjs_name LIKE :search OR cl_scobjs_type LIKE :search OR cl_scobjs_subtype LIKE :search OR cl_scobjs_uuid LIKE :search)
|
||||
AND cl_scobjs_id NOT IN (
|
||||
SELECT cl_scitemcustom_obj_id
|
||||
FROM tbl_scitemcustom
|
||||
WHERE cl_scitemcustom_owner_auth_id = :owner_auth_id
|
||||
)
|
||||
ORDER BY cl_scobjs_name ASC
|
||||
LIMIT 15"
|
||||
);
|
||||
$stmt_search->execute([
|
||||
'search' => '%' . $search . '%',
|
||||
'owner_auth_id' => $current_owner_auth_id,
|
||||
]);
|
||||
$search_results = $stmt_search->fetchAll();
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET' && (string) ($_GET['ajax'] ?? '') === 'item_suggestions') {
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
|
||||
$query = trim((string) ($_GET['q'] ?? ''));
|
||||
$items = [];
|
||||
|
||||
if ($query !== '') {
|
||||
$items = array_map(static function (array $row): array {
|
||||
return [
|
||||
'id' => (int) $row['cl_scobjs_id'],
|
||||
'name' => (string) $row['cl_scobjs_name'],
|
||||
'uuid' => (string) $row['cl_scobjs_uuid'],
|
||||
'type' => (string) $row['cl_scobjs_type'],
|
||||
'subtype' => (string) ($row['cl_scobjs_subtype'] ?? ''),
|
||||
];
|
||||
}, scitemcustom_search_available_items($db, $current_owner_auth_id, $query, 12));
|
||||
}
|
||||
|
||||
echo json_encode(['items' => $items], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
exit;
|
||||
}
|
||||
|
||||
$search = trim($_GET['search'] ?? '');
|
||||
$search_results = $search !== ''
|
||||
? scitemcustom_search_available_items($db, $current_owner_auth_id, $search, 15)
|
||||
: [];
|
||||
|
||||
$stmt_stats_catalog = $db->query('SELECT * FROM tbl_scstatsitem ORDER BY cl_scstatsitem_name ASC, cl_scstatsitem_id ASC');
|
||||
$stats_catalog = $stmt_stats_catalog->fetchAll();
|
||||
$stats_by_id = [];
|
||||
@ -597,6 +670,105 @@ $current_session_user = $_SESSION['user'] ?? '';
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.item-picker-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.9rem;
|
||||
}
|
||||
|
||||
.item-picker-wrap {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.item-picker-input {
|
||||
padding-right: 3rem;
|
||||
}
|
||||
|
||||
.item-picker-dropdown {
|
||||
position: absolute;
|
||||
top: calc(100% + 0.45rem);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 20;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.65rem;
|
||||
max-height: 360px;
|
||||
overflow-y: auto;
|
||||
padding: 0.75rem;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(162, 155, 120, 0.22);
|
||||
background: rgba(17, 24, 39, 0.96);
|
||||
box-shadow: 0 18px 45px rgba(0, 0, 0, 0.42);
|
||||
backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
.item-picker-option {
|
||||
display: flex;
|
||||
gap: 0.85rem;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
border: 1px solid rgba(255, 255, 255, 0.07);
|
||||
border-radius: 10px;
|
||||
padding: 0.8rem;
|
||||
background: rgba(255, 255, 255, 0.035);
|
||||
color: inherit;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.18s ease, background 0.18s ease, transform 0.18s ease;
|
||||
}
|
||||
|
||||
.item-picker-option:hover,
|
||||
.item-picker-option:focus-visible,
|
||||
.item-picker-option.is-active {
|
||||
outline: none;
|
||||
border-color: rgba(162, 155, 120, 0.55);
|
||||
background: rgba(162, 155, 120, 0.09);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.item-picker-option-empty {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.item-picker-option-empty:hover,
|
||||
.item-picker-option-empty:focus-visible {
|
||||
transform: none;
|
||||
border-color: rgba(255, 255, 255, 0.07);
|
||||
background: rgba(255, 255, 255, 0.035);
|
||||
}
|
||||
|
||||
.item-picker-selection {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.9rem;
|
||||
border: 1px solid rgba(162, 155, 120, 0.22);
|
||||
border-radius: 12px;
|
||||
padding: 0.85rem 1rem;
|
||||
background: rgba(162, 155, 120, 0.06);
|
||||
}
|
||||
|
||||
.item-picker-selection-main {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.9rem;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item-picker-actions {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.item-picker-actions .btn-modern[disabled] {
|
||||
opacity: 0.55;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.search-item,
|
||||
.custom-item-card {
|
||||
border: 1px solid var(--border-glow);
|
||||
@ -908,6 +1080,20 @@ $current_session_user = $_SESSION['user'] ?? '';
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.item-picker-selection {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.item-picker-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.item-picker-actions .btn-modern {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.actions-row {
|
||||
justify-content: stretch;
|
||||
}
|
||||
@ -956,14 +1142,57 @@ $current_session_user = $_SESSION['user'] ?? '';
|
||||
<section class="glass-card">
|
||||
<h2>Ajouter un objet</h2>
|
||||
<p class="count-note">Choisis un objet depuis la base, puis attribue-lui autant de stats que nécessaire.</p>
|
||||
<form method="get" action="scitemcustom.php" style="display:flex; gap:0.75rem; flex-wrap:wrap;">
|
||||
<input type="text" name="search" class="form-control" value="<?php echo htmlspecialchars($search, ENT_QUOTES, 'UTF-8'); ?>" placeholder="Rechercher un objet..." style="flex:1; min-width:220px;">
|
||||
<button type="submit" class="btn-modern">Rechercher</button>
|
||||
<a href="scitemcustom.php" class="btn-modern danger">Reset</a>
|
||||
|
||||
<form method="post" action="scitemcustom.php" id="item-add-form" class="item-picker-form" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<input type="hidden" name="action" value="add_custom_item">
|
||||
<input type="hidden" name="obj_id" id="item-add-selected-id" value="">
|
||||
|
||||
<div class="item-picker-wrap">
|
||||
<input
|
||||
type="search"
|
||||
id="item-add-search"
|
||||
class="form-control item-picker-input"
|
||||
placeholder="Rechercher un objet à ajouter..."
|
||||
aria-label="Rechercher un objet à ajouter"
|
||||
aria-autocomplete="list"
|
||||
aria-expanded="false"
|
||||
aria-controls="item-add-suggestions"
|
||||
spellcheck="false"
|
||||
>
|
||||
<div class="item-picker-dropdown hidden-by-filter" id="item-add-suggestions" role="listbox" aria-label="Suggestions d'objets"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-help" id="item-add-help">Commence à taper le nom d'un objet. La liste juste en dessous se met à jour dynamiquement et tu peux cliquer sur l'objet voulu.</div>
|
||||
|
||||
<div class="item-picker-selection hidden-by-filter" id="item-add-selection" aria-live="polite">
|
||||
<div class="item-picker-selection-main">
|
||||
<img src="" class="item-preview hidden-by-filter" id="item-add-selection-image" alt="">
|
||||
<div class="search-item-content">
|
||||
<strong class="item-name" id="item-add-selection-name"></strong>
|
||||
<div class="item-submeta" id="item-add-selection-meta"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn-modern danger" id="item-add-clear">Effacer</button>
|
||||
</div>
|
||||
|
||||
<div class="item-picker-actions">
|
||||
<button type="submit" class="btn-modern" id="item-add-submit" disabled>Ajouter</button>
|
||||
<button type="button" class="btn-modern danger" id="item-add-reset">Vider la recherche</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<noscript>
|
||||
<div class="form-help" style="margin-top:1rem; margin-bottom:0.75rem;">JavaScript est désactivé : utilise la recherche classique ci-dessous.</div>
|
||||
<form method="get" action="scitemcustom.php" style="display:flex; gap:0.75rem; flex-wrap:wrap;">
|
||||
<input type="text" name="search" class="form-control" value="<?php echo htmlspecialchars($search, ENT_QUOTES, 'UTF-8'); ?>" placeholder="Rechercher un objet..." style="flex:1; min-width:220px;">
|
||||
<button type="submit" class="btn-modern">Rechercher</button>
|
||||
<a href="scitemcustom.php" class="btn-modern danger">Reset</a>
|
||||
</form>
|
||||
</noscript>
|
||||
|
||||
<?php if ($search !== ''): ?>
|
||||
<div class="form-help" style="margin-top:1rem; margin-bottom:1rem;">Résultats disponibles pour l'ajout dans la liste Item Custom.</div>
|
||||
<div class="form-help" style="margin-top:1rem; margin-bottom:1rem;">Résultats de la recherche classique pour l'ajout dans la liste Item Custom.</div>
|
||||
<div class="search-result-list">
|
||||
<?php if (empty($search_results)): ?>
|
||||
<div class="search-item">
|
||||
@ -1215,9 +1444,20 @@ $current_session_user = $_SESSION['user'] ?? '';
|
||||
var emptyState = document.getElementById('item-custom-no-results');
|
||||
var itemCards = Array.prototype.slice.call(document.querySelectorAll('#item-custom-list .custom-item-card'));
|
||||
|
||||
if (itemCards.length === 0) {
|
||||
return;
|
||||
}
|
||||
var addForm = document.getElementById('item-add-form');
|
||||
var addSearchInput = document.getElementById('item-add-search');
|
||||
var addSelectedIdInput = document.getElementById('item-add-selected-id');
|
||||
var addDropdown = document.getElementById('item-add-suggestions');
|
||||
var addSelection = document.getElementById('item-add-selection');
|
||||
var addSelectionImage = document.getElementById('item-add-selection-image');
|
||||
var addSelectionName = document.getElementById('item-add-selection-name');
|
||||
var addSelectionMeta = document.getElementById('item-add-selection-meta');
|
||||
var addSubmit = document.getElementById('item-add-submit');
|
||||
var addReset = document.getElementById('item-add-reset');
|
||||
var addClear = document.getElementById('item-add-clear');
|
||||
var pickerRequestTimer = null;
|
||||
var pickerRequestToken = 0;
|
||||
var selectedItem = null;
|
||||
|
||||
function normalizeValue(value) {
|
||||
return (value || '')
|
||||
@ -1228,6 +1468,240 @@ $current_session_user = $_SESSION['user'] ?? '';
|
||||
.trim();
|
||||
}
|
||||
|
||||
function escapeHtml(value) {
|
||||
return (value || '')
|
||||
.toString()
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function setPickerExpanded(isExpanded) {
|
||||
if (addSearchInput) {
|
||||
addSearchInput.setAttribute('aria-expanded', isExpanded ? 'true' : 'false');
|
||||
}
|
||||
}
|
||||
|
||||
function hidePickerDropdown() {
|
||||
if (!addDropdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
addDropdown.innerHTML = '';
|
||||
addDropdown.classList.add('hidden-by-filter');
|
||||
setPickerExpanded(false);
|
||||
}
|
||||
|
||||
function showPickerDropdown() {
|
||||
if (!addDropdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
addDropdown.classList.remove('hidden-by-filter');
|
||||
setPickerExpanded(true);
|
||||
}
|
||||
|
||||
function updateSelectedItem(item) {
|
||||
selectedItem = item || null;
|
||||
|
||||
if (!addSelectedIdInput || !addSubmit || !addSelection || !addSelectionName || !addSelectionMeta || !addSelectionImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selectedItem) {
|
||||
addSelectedIdInput.value = '';
|
||||
addSubmit.disabled = true;
|
||||
addSelection.classList.add('hidden-by-filter');
|
||||
addSelectionName.textContent = '';
|
||||
addSelectionMeta.textContent = '';
|
||||
addSelectionImage.classList.add('hidden-by-filter');
|
||||
addSelectionImage.setAttribute('src', '');
|
||||
addSelectionImage.setAttribute('alt', '');
|
||||
return;
|
||||
}
|
||||
|
||||
addSelectedIdInput.value = String(selectedItem.id || '');
|
||||
addSubmit.disabled = !addSelectedIdInput.value;
|
||||
addSelection.classList.remove('hidden-by-filter');
|
||||
addSelectionName.textContent = selectedItem.name || '';
|
||||
|
||||
var meta = selectedItem.type || '';
|
||||
if (selectedItem.subtype) {
|
||||
meta += (meta ? ' / ' : '') + selectedItem.subtype;
|
||||
}
|
||||
if (selectedItem.uuid) {
|
||||
meta += (meta ? ' — ' : '') + selectedItem.uuid;
|
||||
}
|
||||
addSelectionMeta.textContent = meta;
|
||||
|
||||
if (selectedItem.uuid) {
|
||||
addSelectionImage.classList.remove('hidden-by-filter');
|
||||
addSelectionImage.setAttribute('src', 'https://cstone.space/uifimages/' + encodeURIComponent(selectedItem.uuid) + '.png');
|
||||
addSelectionImage.setAttribute('alt', selectedItem.name || 'Objet sélectionné');
|
||||
} else {
|
||||
addSelectionImage.classList.add('hidden-by-filter');
|
||||
addSelectionImage.setAttribute('src', '');
|
||||
addSelectionImage.setAttribute('alt', '');
|
||||
}
|
||||
}
|
||||
|
||||
function renderPickerItems(items, query) {
|
||||
if (!addDropdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Array.isArray(items) || items.length === 0) {
|
||||
addDropdown.innerHTML = '\n <div class="item-picker-option item-picker-option-empty" role="option" aria-disabled="true">\n <div class="search-item-content">\n <strong class="item-name">Aucun objet trouvé</strong>\n <div class="item-submeta">Aucun objet disponible pour “' + escapeHtml(query) + '”.</div>\n </div>\n </div>';
|
||||
showPickerDropdown();
|
||||
return;
|
||||
}
|
||||
|
||||
addDropdown.innerHTML = items.map(function (item, index) {
|
||||
var meta = escapeHtml(item.type || '');
|
||||
if (item.subtype) {
|
||||
meta += (meta ? ' / ' : '') + escapeHtml(item.subtype);
|
||||
}
|
||||
if (item.uuid) {
|
||||
meta += (meta ? '<br>' : '') + escapeHtml(item.uuid);
|
||||
}
|
||||
|
||||
return '' +
|
||||
'<button type="button" class="item-picker-option' + (index === 0 ? ' is-active' : '') + '" role="option" data-item-id="' + escapeHtml(item.id) + '" data-item-name="' + escapeHtml(item.name) + '" data-item-type="' + escapeHtml(item.type || '') + '" data-item-subtype="' + escapeHtml(item.subtype || '') + '" data-item-uuid="' + escapeHtml(item.uuid || '') + '">' +
|
||||
'<img src="https://cstone.space/uifimages/' + encodeURIComponent(item.uuid || '') + '.png" class="item-preview" alt="">' +
|
||||
'<div class="search-item-content">' +
|
||||
'<strong class="item-name">' + escapeHtml(item.name || '') + '</strong>' +
|
||||
'<div class="item-submeta">' + meta + '</div>' +
|
||||
'</div>' +
|
||||
'</button>';
|
||||
}).join('');
|
||||
|
||||
showPickerDropdown();
|
||||
}
|
||||
|
||||
function fetchPickerSuggestions(query) {
|
||||
if (!addDropdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
var trimmedQuery = (query || '').trim();
|
||||
if (trimmedQuery === '') {
|
||||
hidePickerDropdown();
|
||||
return;
|
||||
}
|
||||
|
||||
var requestToken = ++pickerRequestToken;
|
||||
addDropdown.innerHTML = '\n <div class="item-picker-option item-picker-option-empty" role="option" aria-disabled="true">\n <div class="search-item-content">\n <strong class="item-name">Recherche en cours...</strong>\n <div class="item-submeta">Chargement des objets disponibles.</div>\n </div>\n </div>';
|
||||
showPickerDropdown();
|
||||
|
||||
fetch('scitemcustom.php?ajax=item_suggestions&q=' + encodeURIComponent(trimmedQuery), {
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
credentials: 'same-origin'
|
||||
})
|
||||
.then(function (response) {
|
||||
if (!response.ok) {
|
||||
throw new Error('HTTP ' + response.status);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(function (payload) {
|
||||
if (requestToken !== pickerRequestToken) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderPickerItems(payload && Array.isArray(payload.items) ? payload.items : [], trimmedQuery);
|
||||
})
|
||||
.catch(function () {
|
||||
if (requestToken !== pickerRequestToken) {
|
||||
return;
|
||||
}
|
||||
|
||||
addDropdown.innerHTML = '\n <div class="item-picker-option item-picker-option-empty" role="option" aria-disabled="true">\n <div class="search-item-content">\n <strong class="item-name">Recherche indisponible</strong>\n <div class="item-submeta">Impossible de charger les suggestions pour le moment.</div>\n </div>\n </div>';
|
||||
showPickerDropdown();
|
||||
});
|
||||
}
|
||||
|
||||
function clearSelection(options) {
|
||||
var settings = options || {};
|
||||
updateSelectedItem(null);
|
||||
if (!settings.keepInput && addSearchInput) {
|
||||
addSearchInput.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (addForm && addSearchInput && addSelectedIdInput && addDropdown && addSelection && addSubmit && addReset && addClear) {
|
||||
addSearchInput.addEventListener('input', function () {
|
||||
clearSelection({ keepInput: true });
|
||||
|
||||
var query = addSearchInput.value || '';
|
||||
window.clearTimeout(pickerRequestTimer);
|
||||
pickerRequestTimer = window.setTimeout(function () {
|
||||
fetchPickerSuggestions(query);
|
||||
}, 120);
|
||||
});
|
||||
|
||||
addSearchInput.addEventListener('focus', function () {
|
||||
if ((addSearchInput.value || '').trim() !== '' && addDropdown.innerHTML.trim() !== '') {
|
||||
showPickerDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
addSearchInput.addEventListener('keydown', function (event) {
|
||||
if (event.key === 'Escape') {
|
||||
hidePickerDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
addDropdown.addEventListener('click', function (event) {
|
||||
var option = event.target.closest('.item-picker-option[data-item-id]');
|
||||
if (!option) {
|
||||
return;
|
||||
}
|
||||
|
||||
var item = {
|
||||
id: option.getAttribute('data-item-id') || '',
|
||||
name: option.getAttribute('data-item-name') || '',
|
||||
type: option.getAttribute('data-item-type') || '',
|
||||
subtype: option.getAttribute('data-item-subtype') || '',
|
||||
uuid: option.getAttribute('data-item-uuid') || ''
|
||||
};
|
||||
|
||||
addSearchInput.value = item.name || '';
|
||||
updateSelectedItem(item);
|
||||
hidePickerDropdown();
|
||||
});
|
||||
|
||||
document.addEventListener('click', function (event) {
|
||||
if (!event.target.closest('#item-add-form')) {
|
||||
hidePickerDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
addReset.addEventListener('click', function () {
|
||||
window.clearTimeout(pickerRequestTimer);
|
||||
pickerRequestToken += 1;
|
||||
clearSelection();
|
||||
hidePickerDropdown();
|
||||
addSearchInput.focus();
|
||||
});
|
||||
|
||||
addClear.addEventListener('click', function () {
|
||||
clearSelection();
|
||||
hidePickerDropdown();
|
||||
addSearchInput.focus();
|
||||
});
|
||||
|
||||
addForm.addEventListener('submit', function (event) {
|
||||
if (!addSelectedIdInput.value) {
|
||||
event.preventDefault();
|
||||
addSearchInput.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setCardState(card, isOpen) {
|
||||
var body = card.querySelector('.custom-item-body');
|
||||
var toggleButton = card.querySelector('.item-toggle-btn');
|
||||
@ -1314,10 +1788,12 @@ $current_session_user = $_SESSION['user'] ?? '';
|
||||
});
|
||||
});
|
||||
|
||||
syncFromHash();
|
||||
window.addEventListener('hashchange', syncFromHash);
|
||||
if (itemCards.length > 0) {
|
||||
syncFromHash();
|
||||
window.addEventListener('hashchange', syncFromHash);
|
||||
}
|
||||
|
||||
if (!filterInput || !resetButton || !visibleCount || !emptyState) {
|
||||
if (!filterInput || !resetButton || !visibleCount || !emptyState || itemCards.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user