A simple, persistent notepad and to-do list in a slide-out panel for Torn PDA.
// ==UserScript==
// @name BJ's Torn PDA - Notes & To-Do List
// @namespace http://tampermonkey.net/
// @version 1.0
// @description A simple, persistent notepad and to-do list in a slide-out panel for Torn PDA.
// @author BazookaJoe
// @match https://www.torn.com/*
// @require https://code.jquery.com/jquery-3.7.1.min.js
// ==/UserScript==
/* globals jQuery, $ */
(function() {
'use-strict';
// --- 1. CONFIGURATION & STORAGE KEYS ---
const STORAGE_KEYS = {
PANEL_OPEN: 'pda_notes_panel_isOpen',
NOTES_CONTENT: 'pda_notes_content_v1',
TODO_LIST: 'pda_todo_list_v1'
};
let todoItems = []; // This will hold our list of to-do objects
// --- 2. STYLING ---
function addStyles() {
const styles = `
#pda-notes-container {
position: fixed;
top: 70px; /* Position it high on the page */
right: -320px; /* Start off-screen */
width: 320px;
z-index: 10005;
transition: right 0.3s ease-in-out;
font-family: Arial, sans-serif;
color: #333;
}
#pda-notes-container.expanded {
right: 0;
}
#pda-notes-panel {
background: #f7f7f7;
border: 2px solid #6c757d; /* Grey theme */
border-right: none;
padding: 0;
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
box-shadow: -2px 2px 10px rgba(0,0,0,0.4);
height: calc(100vh - 90px);
display: flex;
flex-direction: column;
}
#pda-notes-panel h4 {
margin: 0; padding: 10px; font-size: 16px;
background-color: #e9ecef; border-bottom: 1px solid #dee2e6;
flex-shrink: 0;
}
.pda-notes-section {
padding: 10px;
border-bottom: 1px solid #dee2e6;
}
#pda-notes-textarea {
width: 100%;
height: 150px;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 4px;
padding: 8px;
font-size: 14px;
resize: vertical;
}
#pda-todo-list {
flex-grow: 1;
overflow-y: auto;
min-height: 100px;
background: #fff;
border: 1px solid #ccc;
padding: 5px;
margin-bottom: 10px;
}
.pda-todo-item {
display: flex;
align-items: center;
padding: 6px;
border-bottom: 1px solid #eee;
}
.pda-todo-item:last-child {
border-bottom: none;
}
.pda-todo-item input[type="checkbox"] {
margin-right: 10px;
}
.pda-todo-item.completed span {
text-decoration: line-through;
color: #888;
}
#pda-todo-input-area { display: flex; gap: 5px; margin-bottom: 10px; }
#pda-todo-new-item { flex-grow: 1; padding: 5px; border: 1px solid #ccc; border-radius: 3px; }
.pda-notes-button {
padding: 5px 10px; border: 1px solid #999;
background-color: #ddd; border-radius: 3px; cursor: pointer;
}
#pda-notes-toggle {
position: fixed;
top: 70px; /* Match panel top */
right: 0;
width: 35px;
height: 50px;
background-color: #6c757d;
color: white;
border: 2px solid #6c757d;
border-right: none;
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 16px;
z-index: 10006;
}
`;
const styleEl = document.createElement('style');
styleEl.textContent = styles;
document.head.appendChild(styleEl);
}
// --- 3. CORE LOGIC ---
function loadData() {
// Load panel state
if (localStorage.getItem(STORAGE_KEYS.PANEL_OPEN) === 'true') {
$('#pda-notes-container').addClass('expanded');
$('#pda-notes-toggle').text('»');
}
// Load notes
const savedNotes = localStorage.getItem(STORAGE_KEYS.NOTES_CONTENT);
if (savedNotes) {
$('#pda-notes-textarea').val(savedNotes);
}
// Load To-Do list
const savedTodos = localStorage.getItem(STORAGE_KEYS.TODO_LIST);
todoItems = savedTodos ? JSON.parse(savedTodos) : [];
renderTodoList();
}
function renderTodoList() {
const listContainer = $('#pda-todo-list');
listContainer.empty(); // Clear existing items before re-rendering
if (todoItems.length === 0) {
listContainer.html('<div style="color: #888; text-align: center; padding: 20px;">No to-do items yet.</div>');
return;
}
todoItems.forEach((item, index) => {
const itemEl = $(`
<div class="pda-todo-item ${item.completed ? 'completed' : ''}" data-index="${index}">
<input type="checkbox" ${item.completed ? 'checked' : ''}>
<span></span>
</div>
`);
itemEl.find('span').text(item.text); // Use .text() to prevent HTML injection
listContainer.append(itemEl);
});
}
function saveTodoList() {
localStorage.setItem(STORAGE_KEYS.TODO_LIST, JSON.stringify(todoItems));
}
// --- 4. UI CREATION & EVENT HANDLERS ---
function createPanel() {
if (document.getElementById('pda-notes-container')) return;
const panelHTML = `
<div id="pda-notes-container">
<div id="pda-notes-panel">
<div class="pda-notes-section">
<h4>Notes</h4>
<textarea id="pda-notes-textarea" placeholder="Your notes here..."></textarea>
</div>
<div class="pda-notes-section" style="display:flex; flex-direction:column; flex-grow: 1;">
<h4>To-Do List</h4>
<div id="pda-todo-list"></div>
<div id="pda-todo-input-area">
<input type="text" id="pda-todo-new-item" placeholder="Add a new task...">
<button id="pda-todo-add-btn" class="pda-notes-button">Add</button>
</div>
<button id="pda-todo-clear-btn" class="pda-notes-button">Clear Checked Items</button>
</div>
</div>
</div>
`;
const toggleButtonHTML = `<div id="pda-notes-toggle">N</div>`;
$('body').append(panelHTML).append(toggleButtonHTML);
// --- Event Handlers ---
// Toggle panel visibility
$('#pda-notes-toggle').on('click', function() {
const container = $('#pda-notes-container');
const isOpen = container.toggleClass('expanded').hasClass('expanded');
$(this).text(isOpen ? '»' : 'N');
localStorage.setItem(STORAGE_KEYS.PANEL_OPEN, isOpen);
});
// Save notes on input
$('#pda-notes-textarea').on('input', function() {
localStorage.setItem(STORAGE_KEYS.NOTES_CONTENT, $(this).val());
});
// Add a to-do item
$('#pda-todo-add-btn').on('click', function() {
const inputEl = $('#pda-todo-new-item');
const newText = inputEl.val().trim();
if (newText) {
todoItems.push({ text: newText, completed: false });
saveTodoList();
renderTodoList();
inputEl.val('').focus();
}
});
// Allow adding with Enter key
$('#pda-todo-new-item').on('keypress', function(e) {
if (e.which === 13) { // Enter key
$('#pda-todo-add-btn').click();
}
});
// Toggle completion status of a to-do item
$('#pda-todo-list').on('change', 'input[type="checkbox"]', function() {
const itemDiv = $(this).closest('.pda-todo-item');
const itemIndex = itemDiv.data('index');
if (typeof itemIndex !== 'undefined' && todoItems[itemIndex]) {
todoItems[itemIndex].completed = this.checked;
itemDiv.toggleClass('completed', this.checked);
saveTodoList();
}
});
// Clear checked items
$('#pda-todo-clear-btn').on('click', function() {
todoItems = todoItems.filter(item => !item.completed);
saveTodoList();
renderTodoList();
});
}
// --- 5. INITIALIZATION ---
function main() {
addStyles();
createPanel();
loadData();
}
// Use a timeout to ensure the Torn page is fully loaded before the script runs
setTimeout(main, 500);
})();