Add Teleport/Effects options to player list
This commit is contained in:
168
public/app.js
168
public/app.js
@ -84,7 +84,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
backupBtn: document.getElementById('backupBtn'),
|
||||
modListSearch: document.getElementById('modListSearch'),
|
||||
clearModListSearch: document.getElementById('clearModListSearch'),
|
||||
modListPagination: document.getElementById('modListPagination')
|
||||
modListPagination: document.getElementById('modListPagination'),
|
||||
teleportModal: document.getElementById('teleportModal'),
|
||||
teleportPlayerName: document.getElementById('teleportPlayerName'),
|
||||
teleportDestination: document.getElementById('teleportDestination'),
|
||||
teleportForm: document.getElementById('teleportForm'),
|
||||
effectModal: document.getElementById('effectModal'),
|
||||
effectPlayerName: document.getElementById('effectPlayerName'),
|
||||
effectSelect: document.getElementById('effectSelect'),
|
||||
effectForm: document.getElementById('effectForm')
|
||||
};
|
||||
|
||||
const loadouts = {
|
||||
@ -168,7 +176,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
geyserStatus: '',
|
||||
sftpStatus: '',
|
||||
activeNotifications: new Map(),
|
||||
allMods: []
|
||||
allMods: [],
|
||||
currentPlayers: []
|
||||
};
|
||||
|
||||
function showNotification(message, type = 'loading', key = null) {
|
||||
@ -646,6 +655,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
if (message.type === 'list-players' && message.data?.players) {
|
||||
const players = message.data.players || [];
|
||||
state.currentPlayers = players;
|
||||
const isSinglePlayer = players.length <= 1;
|
||||
const playerListHtml = players.length > 0
|
||||
? players.map(player => `
|
||||
<div class="flex items-center space-x-4 mb-2">
|
||||
@ -653,6 +664,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<button class="tell-player bg-blue-600 hover:bg-blue-700 px-2 py-1 rounded text-sm" data-player="${player}">Tell</button>
|
||||
<button class="give-player bg-green-600 hover:bg-green-700 px-2 py-1 rounded text-sm" data-player="${player}">Give</button>
|
||||
<button class="teleport-player bg-cyan-600 hover:bg-cyan-700 px-2 py-1 rounded text-sm ${isSinglePlayer ? 'opacity-50 cursor-not-allowed' : ''}" data-player="${player}" ${isSinglePlayer ? 'disabled' : ''}>Teleport</button>
|
||||
<button class="effect-player bg-teal-600 hover:bg-teal-700 px-2 py-1 rounded text-sm" data-player="${player}">Effect</button>
|
||||
<button class="op-player bg-purple-600 hover:bg-purple-700 px-2 py-1 rounded text-sm" data-player="${player}">Op</button>
|
||||
<button class="deop-player bg-purple-600 hover:bg-purple-700 px-2 py-1 rounded text-sm" data-player="${player}">Deop</button>
|
||||
<button class="kick-player bg-red-600 hover:bg-red-700 px-2 py-1 rounded text-sm" data-player="${player}">Kick</button>
|
||||
@ -664,6 +677,66 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (state.playerList !== playerListHtml && elements.playerList) {
|
||||
elements.playerList.innerHTML = playerListHtml;
|
||||
state.playerList = playerListHtml;
|
||||
|
||||
document.querySelectorAll('.tell-player').forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
const player = button.getAttribute('data-player').trim();
|
||||
if (!player) {
|
||||
showNotification('Invalid player name.', 'error');
|
||||
return;
|
||||
}
|
||||
elements.tellPlayerName.textContent = player;
|
||||
elements.tellMessage.value = '';
|
||||
elements.tellModal.classList.remove('hidden');
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.give-player').forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
const player = button.getAttribute('data-player').trim();
|
||||
if (!player) {
|
||||
showNotification('Invalid player name.', 'error');
|
||||
return;
|
||||
}
|
||||
elements.givePlayerName.textContent = player;
|
||||
elements.loadoutSelect.value = 'custom';
|
||||
elements.customGiveFields.classList.remove('hidden');
|
||||
resetItemFields();
|
||||
elements.giveModal.classList.remove('hidden');
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.teleport-player').forEach(button => {
|
||||
if (!button.disabled) {
|
||||
button.addEventListener('click', () => {
|
||||
const player = button.getAttribute('data-player').trim();
|
||||
if (!player) {
|
||||
showNotification('Invalid player name.', 'error');
|
||||
return;
|
||||
}
|
||||
elements.teleportPlayerName.textContent = player;
|
||||
elements.teleportDestination.innerHTML = state.currentPlayers
|
||||
.filter(p => p !== player)
|
||||
.map(p => `<option value="${p}">${p}</option>`)
|
||||
.join('');
|
||||
elements.teleportModal.classList.remove('hidden');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll('.effect-player').forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
const player = button.getAttribute('data-player').trim();
|
||||
if (!player) {
|
||||
showNotification('Invalid player name.', 'error');
|
||||
return;
|
||||
}
|
||||
elements.effectPlayerName.textContent = player;
|
||||
elements.effectSelect.value = 'speed:30:1';
|
||||
elements.effectModal.classList.remove('hidden');
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.kick-player').forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
const player = button.getAttribute('data-player').trim();
|
||||
@ -791,34 +864,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.tell-player').forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
const player = button.getAttribute('data-player').trim();
|
||||
if (!player) {
|
||||
showNotification('Invalid player name.', 'error');
|
||||
return;
|
||||
}
|
||||
elements.tellPlayerName.textContent = player;
|
||||
elements.tellMessage.value = '';
|
||||
elements.tellModal.classList.remove('hidden');
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.give-player').forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
const player = button.getAttribute('data-player').trim();
|
||||
if (!player) {
|
||||
showNotification('Invalid player name.', 'error');
|
||||
return;
|
||||
}
|
||||
elements.givePlayerName.textContent = player;
|
||||
elements.loadoutSelect.value = 'custom';
|
||||
elements.customGiveFields.classList.remove('hidden');
|
||||
resetItemFields();
|
||||
elements.giveModal.classList.remove('hidden');
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1052,7 +1097,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
renderModList();
|
||||
}
|
||||
|
||||
// Debounce function to limit the rate of search execution
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function executedFunction(...args) {
|
||||
@ -1204,6 +1248,49 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
}
|
||||
|
||||
async function sendTeleportCommand() {
|
||||
const player = elements.teleportPlayerName.textContent.trim();
|
||||
const destination = elements.teleportDestination.value.trim();
|
||||
if (!player || !destination) {
|
||||
showNotification('Source and destination players are required.', 'error', 'teleport-error');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const command = `tp ${player} ${destination}`;
|
||||
const key = `action-teleport-player-${player}`;
|
||||
const notification = showNotification(`Teleporting ${player} to ${destination}...`, 'loading', key);
|
||||
const response = await wsRequest('/console', 'POST', { command });
|
||||
updateNotification(notification, `Teleported ${player} to ${destination} successfully`, 'success', key);
|
||||
elements.teleportModal.classList.add('hidden');
|
||||
} catch (error) {
|
||||
console.error(`Teleport ${player} error:`, error);
|
||||
showNotification(`Failed to teleport ${player}: ${error.message}`, 'error', 'teleport-error');
|
||||
}
|
||||
}
|
||||
|
||||
async function sendEffectCommand() {
|
||||
const player = elements.effectPlayerName.textContent.trim();
|
||||
const effectData = elements.effectSelect.value.split(':');
|
||||
const effect = effectData[0];
|
||||
const duration = parseInt(effectData[1], 10);
|
||||
const amplifier = parseInt(effectData[2], 10);
|
||||
if (!player || !effect) {
|
||||
showNotification('Player name and effect are required.', 'error', 'effect-error');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const command = `effect give ${player} minecraft:${effect} ${duration} ${amplifier}`;
|
||||
const key = `action-effect-player-${player}`;
|
||||
const notification = showNotification(`Applying ${effect} to ${player}...`, 'loading', key);
|
||||
const response = await wsRequest('/console', 'POST', { command });
|
||||
updateNotification(notification, `Applied ${effect} to ${player} successfully`, 'success', key);
|
||||
elements.effectModal.classList.add('hidden');
|
||||
} catch (error) {
|
||||
console.error(`Apply effect to ${player} error:`, error);
|
||||
showNotification(`Failed to apply effect to ${player}: ${error.message}`, 'error', 'effect-error');
|
||||
}
|
||||
}
|
||||
|
||||
function addItemField() {
|
||||
const itemList = elements.itemList;
|
||||
const itemEntry = document.createElement('div');
|
||||
@ -1637,6 +1724,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
elements.giveModal.classList.add('hidden');
|
||||
});
|
||||
|
||||
elements.teleportModal.querySelector('.modal-close').addEventListener('click', () => {
|
||||
elements.teleportModal.classList.add('hidden');
|
||||
});
|
||||
|
||||
elements.effectModal.querySelector('.modal-close').addEventListener('click', () => {
|
||||
elements.effectModal.classList.add('hidden');
|
||||
});
|
||||
|
||||
elements.loadoutSelect.addEventListener('change', () => {
|
||||
const isCustom = elements.loadoutSelect.value === 'custom';
|
||||
elements.customGiveFields.classList.toggle('hidden', !isCustom);
|
||||
@ -1659,6 +1754,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
});
|
||||
|
||||
elements.teleportForm.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
sendTeleportCommand();
|
||||
});
|
||||
|
||||
elements.effectForm.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
sendEffectCommand();
|
||||
});
|
||||
|
||||
elements.tellForm.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
sendTellMessage();
|
||||
@ -1684,7 +1789,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
elements.clearModListSearch.addEventListener('click', clearModListSearch);
|
||||
|
||||
// Debounced search for installed mods
|
||||
const debouncedModListSearch = debounce((query) => {
|
||||
modListSearchQuery = query.trim();
|
||||
modListCurrentPage = 1;
|
||||
|
Reference in New Issue
Block a user