primo commit
This commit is contained in:
+263
@@ -0,0 +1,263 @@
|
||||
(() => {
|
||||
'use strict';
|
||||
|
||||
// Doppia sicurezza: attivo solo sul dominio richiesto
|
||||
if (window.location.hostname !== 's170-ar.ogame.gameforge.com') {
|
||||
return;
|
||||
}
|
||||
|
||||
const STORAGE_KEY = 'ogame_notepad_text';
|
||||
const COLLAPSED_KEY = 'ogame_notepad_collapsed';
|
||||
const POS_KEY = 'ogame_notepad_pos';
|
||||
const SIZE_KEY = 'ogame_notepad_size';
|
||||
|
||||
// ---- Creazione elementi ----
|
||||
const container = document.createElement('div');
|
||||
container.id = 'ogame-notepad';
|
||||
|
||||
const header = document.createElement('div');
|
||||
header.className = 'onp-header';
|
||||
header.innerHTML =
|
||||
'<span class="onp-title"><span class="onp-dot"></span>Notepad</span>' +
|
||||
'<span class="onp-actions">' +
|
||||
'<button class="onp-btn" id="onp-collapse" title="Chiudi">✕</button>' +
|
||||
'</span>';
|
||||
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.placeholder = 'Scrivi le tue note qui...';
|
||||
textarea.spellcheck = false;
|
||||
|
||||
const footer = document.createElement('div');
|
||||
footer.className = 'onp-footer';
|
||||
footer.innerHTML =
|
||||
'<span id="onp-count">0 caratteri</span>' +
|
||||
'<span class="onp-status">● Salvato</span>';
|
||||
|
||||
const resizer = document.createElement('div');
|
||||
resizer.className = 'onp-resizer';
|
||||
resizer.title = 'Trascina per ridimensionare';
|
||||
|
||||
container.appendChild(header);
|
||||
container.appendChild(textarea);
|
||||
container.appendChild(footer);
|
||||
container.appendChild(resizer);
|
||||
document.body.appendChild(container);
|
||||
|
||||
// Pulsante per riaprire quando chiuso
|
||||
const toggleBtn = document.createElement('button');
|
||||
toggleBtn.id = 'ogame-notepad-toggle';
|
||||
toggleBtn.innerHTML = '▶';
|
||||
toggleBtn.title = 'Apri notepad';
|
||||
document.body.appendChild(toggleBtn);
|
||||
|
||||
const countEl = footer.querySelector('#onp-count');
|
||||
const statusEl = footer.querySelector('.onp-status');
|
||||
|
||||
// ---- Persistenza ----
|
||||
let saveTimer = null;
|
||||
let dirty = false; // true se ci sono modifiche non ancora salvate
|
||||
let syncing = false; // evita loop quando aggiorniamo da un'altra tab
|
||||
|
||||
function loadNote() {
|
||||
try {
|
||||
const saved = localStorage.getItem(STORAGE_KEY);
|
||||
if (saved !== null) {
|
||||
textarea.value = saved;
|
||||
}
|
||||
} catch (e) {
|
||||
/* storage non disponibile */
|
||||
}
|
||||
updateCount();
|
||||
}
|
||||
|
||||
function saveNote() {
|
||||
dirty = false;
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, textarea.value);
|
||||
statusEl.textContent = '\u25CF Salvato';
|
||||
statusEl.style.color = '#6fbf6f';
|
||||
} catch (e) {
|
||||
statusEl.textContent = '\u26A0 Errore salvataggio';
|
||||
statusEl.style.color = '#e0a050';
|
||||
}
|
||||
}
|
||||
|
||||
function updateCount() {
|
||||
const n = textarea.value.length;
|
||||
countEl.textContent = n + (n === 1 ? ' carattere' : ' caratteri');
|
||||
}
|
||||
|
||||
// Salvataggio automatico con debounce
|
||||
textarea.addEventListener('input', () => {
|
||||
dirty = true;
|
||||
updateCount();
|
||||
statusEl.textContent = '\u25CF Salvataggio...';
|
||||
statusEl.style.color = '#d8d8a0';
|
||||
clearTimeout(saveTimer);
|
||||
saveTimer = setTimeout(saveNote, 400);
|
||||
});
|
||||
|
||||
// Sincronizzazione in tempo reale tra le tab dello stesso dominio.
|
||||
// Quando un'altra tab salva, questa riceve l'evento 'storage' e aggiorna
|
||||
// la textarea, così premendo F5 qui trovi sempre i dati più recenti.
|
||||
window.addEventListener('storage', (e) => {
|
||||
if (e.key !== STORAGE_KEY) return;
|
||||
// Non sovrascrivere mentre l'utente sta digitando in questa tab
|
||||
if (document.activeElement === textarea && dirty) return;
|
||||
syncing = true;
|
||||
textarea.value = e.newValue !== null ? e.newValue : '';
|
||||
updateCount();
|
||||
statusEl.textContent = '\u25CF Salvato';
|
||||
statusEl.style.color = '#6fbf6f';
|
||||
syncing = false;
|
||||
});
|
||||
|
||||
// ---- Trascinamento finestra ----
|
||||
function restorePosition() {
|
||||
try {
|
||||
const saved = localStorage.getItem(POS_KEY);
|
||||
if (saved) {
|
||||
const pos = JSON.parse(saved);
|
||||
if (typeof pos.left === 'number' && typeof pos.top === 'number') {
|
||||
container.style.left = pos.left + 'px';
|
||||
container.style.top = pos.top + 'px';
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function restoreSize() {
|
||||
try {
|
||||
const saved = localStorage.getItem(SIZE_KEY);
|
||||
if (saved) {
|
||||
const size = JSON.parse(saved);
|
||||
if (typeof size.w === 'number') container.style.width = size.w + 'px';
|
||||
if (typeof size.h === 'number') container.style.height = size.h + 'px';
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function makeResizable() {
|
||||
let startX = 0, startY = 0, startW = 0, startH = 0, resizing = false;
|
||||
|
||||
resizer.addEventListener('mousedown', (e) => {
|
||||
resizing = true;
|
||||
startX = e.clientX;
|
||||
startY = e.clientY;
|
||||
startW = container.offsetWidth;
|
||||
startH = container.offsetHeight;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
window.addEventListener('mousemove', (e) => {
|
||||
if (!resizing) return;
|
||||
const newW = Math.max(200, startW + (e.clientX - startX));
|
||||
const newH = Math.max(160, startH + (e.clientY - startY));
|
||||
container.style.width = newW + 'px';
|
||||
container.style.height = newH + 'px';
|
||||
});
|
||||
|
||||
window.addEventListener('mouseup', () => {
|
||||
if (!resizing) return;
|
||||
resizing = false;
|
||||
try {
|
||||
localStorage.setItem(SIZE_KEY, JSON.stringify({
|
||||
w: container.offsetWidth,
|
||||
h: container.offsetHeight
|
||||
}));
|
||||
} catch (e) {}
|
||||
});
|
||||
}
|
||||
|
||||
function makeDraggable() {
|
||||
let dragStartX = 0, dragStartY = 0, origLeft = 0, origTop = 0, dragging = false;
|
||||
|
||||
header.addEventListener('mousedown', (e) => {
|
||||
if (e.target.closest('.onp-btn')) return; // non trascinare quando clicchi i bottoni
|
||||
dragging = true;
|
||||
dragStartX = e.clientX;
|
||||
dragStartY = e.clientY;
|
||||
const rect = container.getBoundingClientRect();
|
||||
origLeft = rect.left;
|
||||
origTop = rect.top;
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
window.addEventListener('mousemove', (e) => {
|
||||
if (!dragging) return;
|
||||
const dx = e.clientX - dragStartX;
|
||||
const dy = e.clientY - dragStartY;
|
||||
container.style.left = (origLeft + dx) + 'px';
|
||||
container.style.top = (origTop + dy) + 'px';
|
||||
});
|
||||
|
||||
window.addEventListener('mouseup', () => {
|
||||
if (!dragging) return;
|
||||
dragging = false;
|
||||
try {
|
||||
localStorage.setItem(POS_KEY, JSON.stringify({
|
||||
left: container.getBoundingClientRect().left,
|
||||
top: container.getBoundingClientRect().top
|
||||
}));
|
||||
} catch (e) {}
|
||||
});
|
||||
}
|
||||
|
||||
// ---- Collapse / expand ----
|
||||
function setCollapsed(collapsed) {
|
||||
container.classList.toggle('collapsed', collapsed);
|
||||
toggleBtn.style.display = collapsed ? 'block' : 'none';
|
||||
try {
|
||||
localStorage.setItem(COLLAPSED_KEY, collapsed ? '1' : '0');
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
header.querySelector('#onp-collapse').addEventListener('click', () => {
|
||||
setCollapsed(true);
|
||||
});
|
||||
|
||||
toggleBtn.addEventListener('click', () => {
|
||||
setCollapsed(false);
|
||||
textarea.focus();
|
||||
});
|
||||
|
||||
// ---- Blocca le scorciatoie di OGame quando il focus è sul notepad ----
|
||||
// Intercetta in fase di cattura così gli handler globali di OGame
|
||||
// (frecce, spazio, invio, ecc.) non reagiscono mentre scrivi.
|
||||
function blockKeysWhileTyping(e) {
|
||||
if (document.activeElement === textarea) {
|
||||
// Blocca SOLO la propagazione verso gli handler globali di OGame,
|
||||
// ma NON chiama preventDefault: così la textarea continua a inserire
|
||||
// caratteri, spostare il cursore, creare nuove righe, ecc.
|
||||
e.stopImmediatePropagation();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
window.addEventListener('keydown', blockKeysWhileTyping, true);
|
||||
window.addEventListener('keyup', blockKeysWhileTyping, true);
|
||||
window.addEventListener('keypress', blockKeysWhileTyping, true);
|
||||
|
||||
// ---- Init ----
|
||||
restorePosition();
|
||||
restoreSize();
|
||||
makeDraggable();
|
||||
makeResizable();
|
||||
loadNote();
|
||||
|
||||
let collapsed = false;
|
||||
try {
|
||||
collapsed = localStorage.getItem(COLLAPSED_KEY) === '1';
|
||||
} catch (e) {}
|
||||
setCollapsed(collapsed);
|
||||
|
||||
// Salva al cambio pagina SOLO se ci sono modifiche non ancora salvate.
|
||||
// In questo modo una tab "stantia" non sovrascrive i dati più recenti
|
||||
// scritti da un'altra tab quando premi F5.
|
||||
window.addEventListener('beforeunload', () => {
|
||||
if (dirty) {
|
||||
clearTimeout(saveTimer);
|
||||
saveNote();
|
||||
}
|
||||
});
|
||||
})();
|
||||
Reference in New Issue
Block a user