modified: templates/itemeditor_command_storage.html
This commit is contained in:
@@ -77,6 +77,12 @@
|
|||||||
<i class="fas fa-plus"></i> Store Another Command
|
<i class="fas fa-plus"></i> Store Another Command
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Recently Stored Commands Section -->
|
||||||
|
<div id="recentCommandsSection" class="recent-commands-section" style="margin-top:2.5rem;">
|
||||||
|
<h3 style="color:#00d4ff; margin-bottom:1rem;">Recently Stored Commands</h3>
|
||||||
|
<div id="recentCommandsList" class="recent-commands-list"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Right: Info & Stats -->
|
<!-- Right: Info & Stats -->
|
||||||
@@ -436,6 +442,51 @@ if (isset($_GET['id'])) {
|
|||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.recent-commands-section {
|
||||||
|
background: #181818;
|
||||||
|
border:1px solid #232323;
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 1.5rem;
|
||||||
|
margin-top: 2.5rem;
|
||||||
|
}
|
||||||
|
.recent-commands-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.2rem;
|
||||||
|
}
|
||||||
|
.recent-command-card {
|
||||||
|
background: #222;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 1rem 1.2rem;
|
||||||
|
}
|
||||||
|
.recent-command-row {
|
||||||
|
display: flex;
|
||||||
|
gap: .7rem;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: .3rem;
|
||||||
|
}
|
||||||
|
.recent-command-label {
|
||||||
|
color: #00d4ff;
|
||||||
|
font-size: .95rem;
|
||||||
|
min-width: 80px;
|
||||||
|
}
|
||||||
|
.recent-command-value {
|
||||||
|
color: #fff;
|
||||||
|
font-size: .97rem;
|
||||||
|
}
|
||||||
|
.recent-command-link {
|
||||||
|
color: #00ffa6;
|
||||||
|
font-size: .97rem;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
.recent-command-timer {
|
||||||
|
color: #ffaa00;
|
||||||
|
font-size: .97rem;
|
||||||
|
}
|
||||||
|
.recent-command-text {
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 992px) {
|
||||||
.storage-grid {
|
.storage-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
@@ -541,6 +592,8 @@ function resetForm() {
|
|||||||
charStatus.textContent = '';
|
charStatus.textContent = '';
|
||||||
submitBtn.disabled = false;
|
submitBtn.disabled = false;
|
||||||
submitBtn.innerHTML = '<i class="fas fa-save"></i> Store Command';
|
submitBtn.innerHTML = '<i class="fas fa-save"></i> Store Command';
|
||||||
|
document.getElementById('generatedLink').value = '';
|
||||||
|
document.getElementById('expiryTime').textContent = '30 minutes';
|
||||||
}
|
}
|
||||||
|
|
||||||
function startCountdown(expiresAt) {
|
function startCountdown(expiresAt) {
|
||||||
@@ -573,5 +626,112 @@ function startCountdown(expiresAt) {
|
|||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Recent Commands Storage (localStorage) ---
|
||||||
|
function getRecentCommands() {
|
||||||
|
let cmds = [];
|
||||||
|
try {
|
||||||
|
cmds = JSON.parse(localStorage.getItem('recentCommands') || '[]');
|
||||||
|
} catch {}
|
||||||
|
return Array.isArray(cmds) ? cmds : [];
|
||||||
|
}
|
||||||
|
function setRecentCommands(cmds) {
|
||||||
|
localStorage.setItem('recentCommands', JSON.stringify(cmds));
|
||||||
|
}
|
||||||
|
function addRecentCommand(cmd) {
|
||||||
|
let cmds = getRecentCommands();
|
||||||
|
cmds.unshift(cmd);
|
||||||
|
cmds = cmds.filter(c => c && c.expires_at && new Date(c.expires_at).getTime() > Date.now());
|
||||||
|
if (cmds.length > 5) cmds = cmds.slice(0,5);
|
||||||
|
setRecentCommands(cmds);
|
||||||
|
}
|
||||||
|
function renderRecentCommands() {
|
||||||
|
const list = document.getElementById('recentCommandsList');
|
||||||
|
const cmds = getRecentCommands();
|
||||||
|
if (!cmds.length) {
|
||||||
|
list.innerHTML = '<div style="color:#888;">No recent commands.</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
list.innerHTML = '';
|
||||||
|
cmds.forEach((cmd, idx) => {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.className = 'recent-command-card';
|
||||||
|
div.innerHTML = `
|
||||||
|
<div class="recent-command-row">
|
||||||
|
<span class="recent-command-label">Command:</span>
|
||||||
|
<span class="recent-command-value recent-command-text">${cmd.command.length > 60 ? cmd.command.slice(0,60)+'...' : cmd.command}</span>
|
||||||
|
</div>
|
||||||
|
<div class="recent-command-row">
|
||||||
|
<span class="recent-command-label">Link:</span>
|
||||||
|
<a href="${cmd.url}" target="_blank" class="recent-command-link">${cmd.url}</a>
|
||||||
|
</div>
|
||||||
|
<div class="recent-command-row">
|
||||||
|
<span class="recent-command-label">Expires in:</span>
|
||||||
|
<span class="recent-command-timer" id="recent-timer-${idx}"></span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
list.appendChild(div);
|
||||||
|
startRecentCountdown(cmd.expires_at, `recent-timer-${idx}`, cmd.url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function startRecentCountdown(expiresAt, elemId, url) {
|
||||||
|
const el = document.getElementById(elemId);
|
||||||
|
function update() {
|
||||||
|
const now = Date.now();
|
||||||
|
const end = new Date(expiresAt).getTime();
|
||||||
|
const dist = end - now;
|
||||||
|
if (dist < 0) {
|
||||||
|
el.innerHTML = '<span style="color:#ff5555;">Expired</span>';
|
||||||
|
// Remove from localStorage
|
||||||
|
let cmds = getRecentCommands().filter(c => c.url !== url);
|
||||||
|
setRecentCommands(cmds);
|
||||||
|
renderRecentCommands();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const m = Math.floor((dist % (1000*60*60))/(1000*60));
|
||||||
|
const s = Math.floor((dist % (1000*60))/1000);
|
||||||
|
el.textContent = `${m}m ${s}s`;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!update()) return;
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
if (!update()) clearInterval(interval);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// On page load
|
||||||
|
renderRecentCommands();
|
||||||
|
|
||||||
|
// On successful store, add to recent
|
||||||
|
const origSuccessHandler = function(data) {
|
||||||
|
addRecentCommand({
|
||||||
|
command: textarea.value.trim(),
|
||||||
|
url: data.url,
|
||||||
|
expires_at: data.expires_at
|
||||||
|
});
|
||||||
|
renderRecentCommands();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Patch the form submit handler to call origSuccessHandler
|
||||||
|
const origSubmit = commandForm.onsubmit;
|
||||||
|
commandForm.onsubmit = function(e) {
|
||||||
|
if (origSubmit) origSubmit.call(this, e);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Patch the fetch success in the submit handler
|
||||||
|
const origFetch = window.fetch;
|
||||||
|
window.fetch = async function() {
|
||||||
|
const res = await origFetch.apply(this, arguments);
|
||||||
|
if (arguments[0] && arguments[0].toString().includes('/projects/itemeditor/storage')) {
|
||||||
|
try {
|
||||||
|
const clone = res.clone();
|
||||||
|
const data = await clone.json();
|
||||||
|
if (data.success && textarea && textarea.value) {
|
||||||
|
origSuccessHandler(data);
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user