some more fancy shit to make it auto update without having to press enter
This commit is contained in:
@@ -4,6 +4,7 @@ import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -11,10 +12,15 @@ import java.util.ArrayList;
|
||||
public class WebServer {
|
||||
|
||||
@GetMapping("/")
|
||||
public String index(@RequestParam(value = "fuzzySearch", required = false) String fuzzySearch, Model model) {
|
||||
// Call your BonusManager or service to get items
|
||||
ArrayList<BonusItem> items = BonusManager.getBonusItems(fuzzySearch);
|
||||
model.addAttribute("items", items);
|
||||
public String index() {
|
||||
return "index";
|
||||
}
|
||||
|
||||
@GetMapping("/api/fuzzy")
|
||||
@ResponseBody
|
||||
public ArrayList<BonusItem> index(@RequestParam(value = "q", required = true) String fuzzySearch, Model model){
|
||||
// Call your BonusManager or service to get items
|
||||
ArrayList<BonusItem> items = BonusManager.getBonusItems(fuzzySearch);
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,25 @@
|
||||
padding: 20px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
form {
|
||||
.search-container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
input[type="text"] {
|
||||
padding: 8px;
|
||||
width: 300px;
|
||||
font-size: 14px;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 4px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
input[type="text"]:focus {
|
||||
outline: none;
|
||||
border-color: #4CAF50;
|
||||
}
|
||||
.search-info {
|
||||
margin-top: 10px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
@@ -50,14 +62,44 @@
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.no-results {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: #999;
|
||||
font-size: 16px;
|
||||
}
|
||||
.score-badge {
|
||||
display: inline-block;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-left: 8px;
|
||||
}
|
||||
.score-badge.medium {
|
||||
background-color: #ff9800;
|
||||
}
|
||||
.score-badge.low {
|
||||
background-color: #f44336;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Appie Bonus Items</h1>
|
||||
|
||||
<form action="">
|
||||
<input type="text" name="fuzzySearch" placeholder="Search items...">
|
||||
</form>
|
||||
<div class="search-container">
|
||||
<input
|
||||
type="text"
|
||||
id="fuzzySearch"
|
||||
placeholder="Search items... (real-time)"
|
||||
autocomplete="off"
|
||||
>
|
||||
<div class="search-info">
|
||||
<span id="resultCount">Showing all items</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
@@ -70,7 +112,7 @@
|
||||
<th>More Info</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody id="tableBody">
|
||||
<tr th:each="item : ${items}">
|
||||
<td th:text="${item.title}">Item Name</td>
|
||||
<td th:text="${item.description}">Description</td>
|
||||
@@ -85,5 +127,93 @@
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script>
|
||||
const searchInput = document.getElementById('fuzzySearch');
|
||||
const tableBody = document.getElementById('tableBody');
|
||||
const resultCount = document.getElementById('resultCount');
|
||||
let debounceTimer;
|
||||
|
||||
searchInput.addEventListener('input', (e) => {
|
||||
clearTimeout(debounceTimer);
|
||||
const query = e.target.value.trim();
|
||||
|
||||
// Debounce: wait 300ms before searching
|
||||
debounceTimer = setTimeout(() => {
|
||||
if (query.length === 0) {
|
||||
// Reset to all items
|
||||
location.reload();
|
||||
} else {
|
||||
performFuzzySearch(query);
|
||||
}
|
||||
}, 300);
|
||||
});
|
||||
|
||||
async function performFuzzySearch(query) {
|
||||
try {
|
||||
const response = await fetch(`/api/fuzzy?q=${encodeURIComponent(query)}`);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error('Search failed:', response.status);
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await response.json();
|
||||
renderResults(results, query);
|
||||
} catch (error) {
|
||||
console.error('Error performing search:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function renderResults(results, query) {
|
||||
if (results.length === 0) {
|
||||
tableBody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="6" class="no-results">
|
||||
No items found matching "<strong>${escapeHtml(query)}</strong>"
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
resultCount.textContent = `0 results for "${query}"`;
|
||||
return;
|
||||
}
|
||||
|
||||
tableBody.innerHTML = results.map(item => `
|
||||
<tr>
|
||||
<td>
|
||||
${escapeHtml(item.title)}
|
||||
</td>
|
||||
<td>${escapeHtml(item.description)}</td>
|
||||
<td>${escapeHtml(item.bonusText)}</td>
|
||||
<td>${escapeHtml(item.category)}</td>
|
||||
<td>
|
||||
<img src="${escapeHtml(item.imageURL)}" alt="${escapeHtml(item.title)}" width="200" height="200">
|
||||
</td>
|
||||
<td>
|
||||
<a href="${escapeHtml(item.moreInfoURL)}" target="_blank">here</a>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
|
||||
resultCount.textContent = `${results.length} result${results.length !== 1 ? 's' : ''} for "${query}"`;
|
||||
}
|
||||
|
||||
function getScoreBadgeClass(score) {
|
||||
if (score >= 90) return ''; // Green (default)
|
||||
if (score >= 70) return 'medium'; // Orange
|
||||
return 'low'; // Red
|
||||
}
|
||||
|
||||
function escapeHtml(text) {
|
||||
const map = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
};
|
||||
return text.replace(/[&<>"']/g, m => map[m]);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user