2.0 - WebUI builder ("Cielight" merge) #9
@ -80,8 +80,6 @@ function renderTags(container, tags, imgIndex) {
|
|||||||
// Suggestion dropdown
|
// Suggestion dropdown
|
||||||
const suggestionBox = document.createElement('ul');
|
const suggestionBox = document.createElement('ul');
|
||||||
suggestionBox.className = 'suggestions';
|
suggestionBox.className = 'suggestions';
|
||||||
suggestionBox.style.fontStyle = 'italic';
|
|
||||||
suggestionBox.style.textAlign = 'left';
|
|
||||||
container.appendChild(suggestionBox);
|
container.appendChild(suggestionBox);
|
||||||
|
|
||||||
let selectedIndex = -1;
|
let selectedIndex = -1;
|
||||||
@ -90,14 +88,22 @@ function renderTags(container, tags, imgIndex) {
|
|||||||
tag = tag.trim();
|
tag = tag.trim();
|
||||||
if (!tag) return;
|
if (!tag) return;
|
||||||
if (!tags.includes(tag)) tags.push(tag);
|
if (!tags.includes(tag)) tags.push(tag);
|
||||||
updateAllTags();
|
updateTags(imgIndex, tags); // save to galleryImages and server
|
||||||
updateTags(imgIndex, tags);
|
|
||||||
renderTags(container, tags, imgIndex);
|
renderTags(container, tags, imgIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateSuggestions = () => {
|
const updateSuggestions = () => {
|
||||||
const value = input.value.toLowerCase();
|
const value = input.value.toLowerCase();
|
||||||
const suggestions = allTags.filter(t => !tags.includes(t) && t.toLowerCase().startsWith(value));
|
|
||||||
|
const allTagsFlat = galleryImages.flatMap(img => img.tags || []);
|
||||||
|
const tagCount = {};
|
||||||
|
allTagsFlat.forEach(t => tagCount[t] = (tagCount[t] || 0) + 1);
|
||||||
|
|
||||||
|
const allTagsSorted = Object.keys(tagCount)
|
||||||
|
.sort((a, b) => tagCount[b] - tagCount[a]);
|
||||||
|
|
||||||
|
// Show suggestions that start with input (or all if empty)
|
||||||
|
const suggestions = allTagsSorted.filter(t => t.toLowerCase().startsWith(value) && !tags.includes(t));
|
||||||
|
|
||||||
suggestionBox.innerHTML = '';
|
suggestionBox.innerHTML = '';
|
||||||
selectedIndex = -1;
|
selectedIndex = -1;
|
||||||
@ -106,10 +112,21 @@ function renderTags(container, tags, imgIndex) {
|
|||||||
suggestionBox.style.display = 'block';
|
suggestionBox.style.display = 'block';
|
||||||
suggestions.forEach((s, idx) => {
|
suggestions.forEach((s, idx) => {
|
||||||
const li = document.createElement('li');
|
const li = document.createElement('li');
|
||||||
|
li.style.fontStyle = 'italic';
|
||||||
|
li.style.textAlign = 'left';
|
||||||
|
|
||||||
const boldPart = `<b>${s.substring(0, input.value.length)}</b>`;
|
const boldPart = `<b>${s.substring(0, input.value.length)}</b>`;
|
||||||
const rest = s.substring(input.value.length);
|
const rest = s.substring(input.value.length);
|
||||||
li.innerHTML = boldPart + rest;
|
li.innerHTML = boldPart + rest;
|
||||||
li.onclick = () => addTag(s);
|
|
||||||
|
li.addEventListener('mousedown', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
addTag(s);
|
||||||
|
input.value = '';
|
||||||
|
input.focus();
|
||||||
|
updateSuggestions();
|
||||||
|
});
|
||||||
|
|
||||||
li.onmouseover = () => selectedIndex = idx;
|
li.onmouseover = () => selectedIndex = idx;
|
||||||
suggestionBox.appendChild(li);
|
suggestionBox.appendChild(li);
|
||||||
});
|
});
|
||||||
@ -119,46 +136,50 @@ function renderTags(container, tags, imgIndex) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
input.addEventListener('input', updateSuggestions);
|
input.addEventListener('input', updateSuggestions);
|
||||||
input.addEventListener('focus', updateSuggestions);
|
|
||||||
|
|
||||||
// Keyboard navigation
|
input.addEventListener('focus', updateSuggestions); // Show suggestions on focus
|
||||||
|
|
||||||
input.addEventListener('keydown', (e) => {
|
input.addEventListener('keydown', (e) => {
|
||||||
const items = suggestionBox.querySelectorAll('li');
|
const items = suggestionBox.querySelectorAll('li');
|
||||||
if (items.length) {
|
|
||||||
if (e.key === 'ArrowDown') {
|
if (e.key === 'ArrowDown') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
if (!items.length) return;
|
||||||
selectedIndex = (selectedIndex + 1) % items.length;
|
selectedIndex = (selectedIndex + 1) % items.length;
|
||||||
items.forEach((li, i) => li.classList.toggle('selected', i === selectedIndex));
|
items.forEach((li, i) => li.classList.toggle('selected', i === selectedIndex));
|
||||||
} else if (e.key === 'ArrowUp') {
|
} else if (e.key === 'ArrowUp') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
if (!items.length) return;
|
||||||
selectedIndex = (selectedIndex - 1 + items.length) % items.length;
|
selectedIndex = (selectedIndex - 1 + items.length) % items.length;
|
||||||
items.forEach((li, i) => li.classList.toggle('selected', i === selectedIndex));
|
items.forEach((li, i) => li.classList.toggle('selected', i === selectedIndex));
|
||||||
} else if (e.key === 'Enter') {
|
} else if (e.key === 'Enter') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (selectedIndex >= 0) addTag(items[selectedIndex].textContent.replace(/×$/,''));
|
if (selectedIndex >= 0 && items[selectedIndex]) {
|
||||||
else addTag(input.value);
|
addTag(items[selectedIndex].textContent);
|
||||||
} else if (e.key === 'Escape') {
|
} else {
|
||||||
suggestionBox.style.display = 'none';
|
addTag(input.value);
|
||||||
|
}
|
||||||
|
input.value = '';
|
||||||
|
updateSuggestions();
|
||||||
} else if ([' ', ','].includes(e.key)) {
|
} else if ([' ', ','].includes(e.key)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
addTag(input.value);
|
addTag(input.value);
|
||||||
}
|
input.value = '';
|
||||||
} else if (['Enter', ' ', ','].includes(e.key)) {
|
updateSuggestions();
|
||||||
e.preventDefault();
|
|
||||||
addTag(input.value);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
input.addEventListener('blur', () => {
|
input.addEventListener('blur', () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (input.value.trim()) addTag(input.value);
|
|
||||||
suggestionBox.style.display = 'none';
|
suggestionBox.style.display = 'none';
|
||||||
}, 100);
|
input.value = ''; // Clear input without saving
|
||||||
|
}, 150);
|
||||||
});
|
});
|
||||||
|
|
||||||
input.focus();
|
input.focus();
|
||||||
|
updateSuggestions(); // show suggestions on render
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- Update tags in galleryImages array ---
|
// --- Update tags in galleryImages array ---
|
||||||
function updateTags(index, tags) {
|
function updateTags(index, tags) {
|
||||||
galleryImages[index].tags = tags;
|
galleryImages[index].tags = tags;
|
||||||
|
Reference in New Issue
Block a user