A few days ago, I was writing a post on this forum. I had already spent quite some time writing it, and the post was almost finished, then I accidentally refreshed the page. After the refresh, I saw that everything I had written was gone. It is worth mentioning that I had not clicked the
Preview Button, so the forum's own draft system had not saved my post either. After this happened, I was thinking that it would be useful to have a simple userscript that automatically saves your draft while you are typing. So I ended up making this small script for myself.
Although Tryninja has already made a
script for this, his script mainly works by using the Preview option. Basically, it calls the Preview button in the background every few seconds and saves the post as a forum draft. Because of this, you still need to go to the Draft option and copy that post again.
Script OverviewThis script automatically saves whatever you are writing while creating a post or reply on Bitcointalk to your browser's local storage. So, even if you accidentally refresh the page, close the tab, or lose the writing area for any other reason, you can restore your saved draft when you open the
same page again.
I know that Bitcointalk's Preview option already saves the post as a draft. This is a very useful feature. But the problem is that we often
forget to click the Preview button while writing. I was having exactly this problem myself.
So I thought, why not make it so that Preview does not need to be done manually? I can simply keep typing, and the script will save the draft automatically.
Features- Draft is automatically saved while typing (Does not use the forum's draft feature)
- Saved draft is automatically restored after refreshing the page. This also means even if you come back to the same reply page after 1 day, your saved post will still be there unless you click the Clear button.
- Drafts older than 7 days are automatically deleted
- Saved draft is automatically deleted after submitting the post
- Shows a warning when the post exceeds the 64,000 character limit, because a forum's post can contain a maximum of 64,000 characters. (This is especially useful for people who write large posts.)
Separate Drafts for Each Post : One of the useful parts of this script is that
each topic or reply page gets its own separate draft. For example, if you're writing a reply on Topic A and then start writing another reply on Topic B, both drafts are saved independently. Your Topic A draft will not overwrite the Topic B draft.
DemoInstallation Process- Install Tampermonkey.
- Create a new script.
- Paste the code below.
- Save the script and reload any Bitcointalk thread.
- Or use the Greasy Fork link for one click installation.
- Now open any Bitcointalk topic and go to the Reply or New Topic page.
- You will see the word/character counter and draft status below the textarea.
For Mobile DevicesThe process is almost the same. You just need to use
Firefox for AndroidThen, when you write a post on Bitcointalk, the script will work automatically.
// ==UserScript==
// @name Bitcointalk Minimalist Auto-Save Draft
// @version 1.0
// @description Auto-save draft with auto-expiration (7 days) and 64,000 character limit warning
// @author Royal Cap
// @match https://bitcointalk.org/index.php?*action=post*
// @match https://bitcointalk.org/index.php?*topic=*
// @grant none
// @license MIT
// @namespace https://greasyfork.org/users/1507638
// ==/UserScript==
(function() {
'useStrict';
const textarea = document.querySelector('textarea[name="message"]');
if (!textarea) return;
const storageKey = 'btt_draft_' + window.location.href;
const warnLimit = 64000; // Bitcointalk maximum post length
const maxAge = 7 * 24 * 60 * 60 * 1000; // Delete After 7 Days
let saveTimeout = null;
const uiContainer = document.createElement('div');
uiContainer.style.cssText = 'margin-top: 4px; font-size: 11px; font-family: verdana, sans-serif; color: #444; display: flex; align-items: center; justify-content: space-between;';
const leftGroup = document.createElement('div');
leftGroup.style.cssText = 'display: flex; align-items: center; gap: 8px;';
const clearBtn = document.createElement('button');
clearBtn.type = 'button';
clearBtn.textContent = 'Clear Draft';
clearBtn.style.cssText = 'padding: 1px 5px; font-size: 12px; font-family: verdana, sans-serif; background: #e0e0e0; color: #000; border: 1px solid #999; cursor: pointer; display: none;';
const statusText = document.createElement('span');
statusText.style.fontStyle = 'italic';
statusText.style.color = '#666';
leftGroup.appendChild(clearBtn);
leftGroup.appendChild(statusText);
const countDisplay = document.createElement('div');
countDisplay.style.cssText = 'font-weight: normal; color: #555; margin-right: 50px;';
uiContainer.appendChild(leftGroup);
uiContainer.appendChild(countDisplay);
textarea.parentNode.insertBefore(uiContainer, textarea.nextSibling);
function updateCounter() {
const text = textarea.value;
const charCount = text.length;
const wordCount = text.trim() ? text.trim().split(/\s+/).length : 0;
if (charCount > warnLimit) {
countDisplay.innerHTML = `<span style="color: red; font-weight: bold;">Words: ${wordCount} | Chars: ${charCount} (Exceeding ${warnLimit} limit!)</span>`;
} else {
countDisplay.innerHTML = `Words: <b>${wordCount}</b> | Chars: <b>${charCount}</b> / ${warnLimit}`;
}
}
function toggleClearBtn() {
const savedData = localStorage.getItem(storageKey);
if (savedData) {
clearBtn.style.display = 'inline-block';
} else {
clearBtn.style.display = 'none';
}
}
const rawData = localStorage.getItem(storageKey);
if (rawData) {
try {
const parsedData = JSON.parse(rawData);
if (Date.now() - parsedData.timestamp > maxAge) {
localStorage.removeItem(storageKey);
statusText.textContent = 'Expired draft deleted';
} else {
textarea.value = parsedData.text;
statusText.textContent = 'Draft restored';
}
} catch (e) {
textarea.value = rawData;
statusText.textContent = 'Draft restored';
}
}
updateCounter();
toggleClearBtn();
textarea.addEventListener('input', function() {
updateCounter();
statusText.textContent = 'Saving...';
clearTimeout(saveTimeout);
saveTimeout = setTimeout(() => {
if (textarea.value.trim() === '') {
localStorage.removeItem(storageKey);
statusText.textContent = 'Draft empty';
} else {
const dataToSave = {
text: textarea.value,
timestamp: Date.now()
};
localStorage.setItem(storageKey, JSON.stringify(dataToSave));
const timeStr = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
statusText.textContent = `Saved at ${timeStr}`;
}
toggleClearBtn();
}, 500);
});
clearBtn.addEventListener('click', function() {
if (confirm('Clear saved draft?')) {
localStorage.removeItem(storageKey);
textarea.value = '';
updateCounter();
statusText.textContent = 'Draft cleared';
toggleClearBtn();
}
});
const form = textarea.closest('form');
if (form) {
form.addEventListener('submit', function() {
localStorage.removeItem(storageKey);
});
}
})();
This script only uses the browser's localStorage. So, if you clear the site's data or local storage, your saved drafts may also be deleted. Another thing is that the draft key is created based on the same URL. So, drafts from different post/reply pages will be stored separately.